Introduction

Methods

Data collection

This sample consists of data for 150 subjects of the original sample of 522 that has completed the initial battery of 37 cognitive tasks, 23 surveys and 3 surveys on demographics. Details of the original sample as well as quality control (qc) procedures are described elsewhere (Eisenberg et al., 2017). Invited participants were chosen randomly and only subsets of them were invited for a given batch (instead of opening the battery to all qualified subjects) with the intention to avoid a potential oversampling and bias towards “high self regulators”.

workers = read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/Local/User_717570_workers.csv')
workers = workers %>% 
  group_by(Worker.ID) %>%
  mutate(Retest_worker=ifelse(sum(CURRENT.RetestWorker,CURRENT.RetestWorkerB2,CURRENT.RetestWorkerB3,CURRENT.RetestWorkerB4,CURRENT.RetestWorkerB5,na.rm=T)>0,1,0)) %>%
  ungroup()

worker_counts <- fromJSON('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/Local/retest_worker_counts.json')

worker_counts = as.data.frame(unlist(worker_counts))
names(worker_counts) = "task_count"

In total 242 participants were invited, 175 began the battery, 157 completed the battery and 150 provided data that passed qc for both time points. Our target sample size was determined in advance of data collection and data collection continued until this number of participants with data that survived qc was reached.

disc_comp_date = read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/Local/discovery_completion_dates.csv', header=FALSE)
val_comp_date = read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/Local/validation_completion_dates.csv', header=FALSE)
test_comp_date = rbind(disc_comp_date, val_comp_date)
rm(disc_comp_date, val_comp_date)
retest_comp_date = read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/Local/retest_completion_dates.csv', header=FALSE)
comp_dates = merge(retest_comp_date, test_comp_date, by="V1")
names(comp_dates) <- c("sub_id", "retest_comp", "test_comp")
comp_dates$retest_comp = as.Date(comp_dates$retest_comp)
comp_dates$test_comp = as.Date(comp_dates$test_comp)
comp_dates$days_btw = with(comp_dates, retest_comp-test_comp)

Data collection took place on average 115 number of days after the completion of the initial battery with a range of 60 to 228 days.

Demographics

test_demog <- read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/t1_data/demographic_health.csv')

retest_demog <- read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/demographic_health.csv')

retest_demog = retest_demog[retest_demog$X %in% test_demog$X,]

names(test_demog)[which(names(test_demog) == 'X')] <-'sub_id'
names(retest_demog)[which(names(retest_demog) == 'X')] <-'sub_id'

summary(retest_demog %>%
          select(Sex, Age))
      Sex             Age      
 Min.   :0.000   Min.   :21.0  
 1st Qu.:0.000   1st Qu.:29.0  
 Median :1.000   Median :33.0  
 Mean   :0.527   Mean   :34.5  
 3rd Qu.:1.000   3rd Qu.:38.8  
 Max.   :1.000   Max.   :60.0  

Literature

One the major contributions of this project is a comprehensive literature review of the retest reliabilities of the surveys and tasks that were used. We reviewed the literature on a measure (as opposed to task level) paying attention to differences in sample size, the delay between the two measurements as well as the statistic that was used to assess reliabilities (e.g. Spearman vs. Pearson correlations). Here we present a table and a visualization summarizing our findings. References mentioned in the table below can be found here.

lit_review <- read.csv('/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/input/lit_review_figure.csv')

lit_review

Measure level plot

lit_review = lit_review %>%
  separate(dv, c("task_group", "var"), sep="\\.",remove=FALSE,extra="merge") %>%
  mutate(task_group = factor(task_group, levels = task_group[order(task)]),
         type = as.character(type)) %>%
  mutate(task_group = gsub("_", " ", task_group),
         var = gsub("_", " ", var)) %>%
  arrange(task_group, raw_fit, var) %>%
  mutate(task_group = ifelse(task_group == "psychological refractory period two choices", "psychological refractory period", ifelse(task_group == "angling risk task always sunny", "angling risk task",task_group))) %>%
  mutate(task_group = gsub("survey", "", task_group)) %>%
    select(-measure_description, -reference)

Because this plot is difficult to digest we summarize it on a task level to give a general sense of the main takeaways. This plot naturally disregards much of the fine grained information.

p1_t_legend <- lit_review %>%
  filter(task == 'task') %>%
ggplot(aes(y = factor(task_group, levels=rev(unique(task_group))), x = retest_reliability)) + 
  geom_point(aes(size=sample_size, shape = type), color='black')+
  theme_bw()+
  theme(axis.text.y = element_text(size=43),
        legend.position = 'bottom',
        axis.text.x = element_text(size=23),
        axis.title.x = element_text(size=30), 
        legend.text = element_text(size=20), 
        legend.key.width = unit(0.75, "inches"), 
        legend.title = element_text(size=28),
        legend.spacing.x = unit(0.5, "inches")) + 
  guides(size = guide_legend(override.aes = list(size=c(9,18,28))),
         shape = guide_legend(override.aes = list(size=18)))+
  xlab("Reliability")+
  ylab("")+
  scale_x_continuous(limits = c(-0.25,1), breaks=c(-0.25, 0, 0.25, 0.5, 0.75, 1))+
  scale_y_discrete(labels = function(x) str_wrap(x, width = 10))+
  scale_shape_manual(breaks = sort(lit_review$type), values = c(15, 16, 17, 3), name="Type")+
  scale_size_continuous(name = "Sample Size")+
  geom_vline(xintercept = 0, color = "red", size = 1)

p1_t <- lit_review %>%
  filter(task == 'task') %>%
ggplot(aes(y = factor(task_group, levels=rev(unique(task_group))), x = retest_reliability)) + 
  geom_point(aes(size=sample_size, shape = type), color='#00BFC4')+
  theme_bw()+
  theme(axis.text.y = element_text(size=43),
        legend.position = 'none',
        axis.text.x = element_text(size=23),
        axis.title.x = element_text(size=30)) + 
  xlab("Reliability")+
  ylab("")+
  scale_x_continuous(limits = c(-0.25,1), breaks=c(-0.25, 0, 0.25, 0.5, 0.75, 1))+
  scale_y_discrete(labels = function(x) str_wrap(x, width = 10))+
  scale_shape_manual(breaks = sort(lit_review$type), values = c(15, 16, 17, 3))+
  scale_size_continuous(range = c(5, 35))+
  geom_vline(xintercept = 0, color = "red", size = 1)

p2_t <- lit_review %>%
  filter(task == 'survey') %>%
ggplot(aes(y = factor(task_group, levels=rev(unique(task_group))), x = retest_reliability)) + 
  geom_point(aes(size=sample_size, shape = type), color='#F8766D')+
  theme_bw()+
  theme(axis.text.y = element_text(size=43),
        legend.position = 'none',
        axis.text.x = element_text(size=23),
        axis.title.x = element_text(size=30)) + 
  xlab("Reliability")+
  ylab("")+
  scale_x_continuous(limits = c(-0.25,1), breaks=c(-0.25, 0, 0.25, 0.5, 0.75, 1))+
  scale_y_discrete(labels = function(x) str_wrap(x, width = 10))+
  scale_shape_manual(breaks = sort(lit_review$type), values = c(15, 16, 17, 3))+
  scale_size_continuous(range = c(5, 35))+
  geom_vline(xintercept = 0, color = "red", size = 1)

mylegend<-g_legend(p1_t_legend)

p3_t <- arrangeGrob(arrangeGrob(p1_t, p2_t, nrow=1), mylegend, nrow=2,heights=c(10, 1))

ggsave('Lit_Review_Plot_t.jpg', plot = p3_t, device = "jpeg", path = "/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/output/figures/", width = 27, height = 48, units = "in", limitsize = FALSE, dpi = 72)
rm(p1_t, p2_t, p3_t, mylegend, p1_t_legend)

An interactive version of this plot could be find here

Takeaways from this review are: - Survey measures have been reported to higher reliability compared to task measures
- Survey measures have less variability in the reported reliabiltiy estimates compared to task measures’

Loading datasets

The variables included in this report are:
- meaningful variables (includes only hdddm parameters)
- EZ diffusion parameters
- Raw RT and Accuracy measures
- Variables found in the literature (for comparison)

Load time 1 data

test_data <- read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/t1_data/variables_exhaustive.csv')

test_data <- test_data[,names(test_data) %in% retest_report_vars]

test_data$X <- as.character(test_data$X)
names(test_data)[which(names(test_data) == 'X')] <-'sub_id' 

For reference here are the variables that are not included in the analyses of the remainder of this report because they were not of theoretical interest in factor structure analyses of this data so far. These include drift diffusion and other model parameters for specific conditions within a task; survey variables that are not part of the dependant variables for that survey in the literature and demographics (these are saved for prediction analyses).

test_data2 <- read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/t1_data/variables_exhaustive.csv')

df <- data.frame(names(test_data2)[which(names(test_data2) %in% names(test_data) == FALSE)])
names(df) = c('vars')

df

Load time 2 data

retest_data <- read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/variables_exhaustive.csv')

retest_data <- retest_data[,names(retest_data) %in% retest_report_vars]

retest_data$X <- as.character(retest_data$X)
names(retest_data)[which(names(retest_data) == 'X')] <-'sub_id' 
retest_data = retest_data[retest_data$sub_id %in% test_data$sub_id,]

Replace HDDM parameters in t1 data

Since HDDM parameters depend on the sample on which they are fit we refit the model on t1 data for the subjects that have t2 data. Here we replace the HDDM parameters in the current t1 dataset with these refitted values.

hddm_refits <- read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_03-21-2017/hddm_refits_exhaustive.csv')

hddm_refits = hddm_refits[,names(hddm_refits) %in% retest_report_vars]

hddm_refits$X <- as.character(hddm_refits$X)
names(hddm_refits)[which(names(hddm_refits) == 'X')] <-'sub_id' 

#For later comparison of whether fitting the DDM parameters on full or retest sample makes a big difference
test_data_full_sample_hddm <- test_data

test_data = cbind(test_data$sub_id, test_data[,names(test_data) %in% names(hddm_refits) == FALSE])

names(test_data)[which(names(test_data) == 'test_data$sub_id')] <-'sub_id'

test_data = merge(test_data, hddm_refits, by="sub_id")

Results

Demographics reliability

Point estimates of reliability for the demographic variabels.

numeric_cols = c()

for(i in 1:length(names(test_demog))){
  if(is.numeric(test_demog[,i])){
    numeric_cols <- c(numeric_cols, names(test_demog)[i])
  }
}

demog_rel_df <- data.frame(spearman = rep(NA, length(numeric_cols)),
                     icc = rep(NA, length(numeric_cols)),
                     pearson = rep(NA, length(numeric_cols)))

row.names(demog_rel_df) <- numeric_cols

for(i in 1:length(numeric_cols)){
  demog_rel_df[numeric_cols[i], 'spearman'] <- get_spearman(numeric_cols[i], t1_df = test_demog, t2_df = retest_demog) 
  demog_rel_df[numeric_cols[i], 'icc'] <- get_icc(numeric_cols[i], t1_df = test_demog, t2_df = retest_demog)
  demog_rel_df[numeric_cols[i], 'pearson'] <- get_pearson(numeric_cols[i], t1_df = test_demog, t2_df = retest_demog)
}

demog_rel_df %>%
  mutate(var = row.names(.)) %>%
  select(var, icc, spearman, pearson) %>%
  arrange(-icc)

Relationship between reliability metrics (point estimates)

Based on Weir (2005) ICC(3,k) does not take in to account within subject differences between two time points (i.e. the fixed effect of time/systematic error). Thus, it is well approximated by Pearson’s r and subject to similar criticisms. Weir (2005) suggests reporting at least this systematic error effect size if one chooses to report with ICC(3,k). Based on his conclusions here I report:
- ICC(3,k): As Dave clarified this ranges from 1 to -1/(number of repeated measures -1) so in our case this range would be [-1, 1]; larger values would mean that the two scores of a subject for a given measure are more similar to each other than they are to scores of other people
- partial \(\eta^2\) for time (\(SS_{time}/SS_{within}\)): effect size of time
- SEM (\(\sqrt(MS_{error})\)): standard error of measurement; the smaller the better

#Create df of point estimate reliabilities
numeric_cols = c()

for(i in 1:length(names(test_data))){
  if(is.numeric(test_data[,i]) & names(test_data)[i] %in% names(retest_data)){
    numeric_cols <- c(numeric_cols, names(test_data)[i])
  }
}

rel_df <- data.frame(spearman = rep(NA, length(numeric_cols)),
                     icc = rep(NA, length(numeric_cols)),
                     pearson = rep(NA, length(numeric_cols)),
                     eta_sq = rep(NA, length(numeric_cols)),
                     sem = rep(NA, length(numeric_cols)),
                     var_subs = rep(NA, length(numeric_cols)),
                     var_ind = rep(NA, length(numeric_cols)),
                     var_resid = rep(NA, length(numeric_cols)))

row.names(rel_df) <- numeric_cols

for(i in 1:length(numeric_cols)){
  rel_df[numeric_cols[i], 'spearman'] <- get_spearman(numeric_cols[i]) 
  rel_df[numeric_cols[i], 'icc'] <- get_icc(numeric_cols[i])
  rel_df[numeric_cols[i], 'pearson'] <- get_pearson(numeric_cols[i])
  rel_df[numeric_cols[i], 'eta_sq'] <- get_eta(numeric_cols[i])
  rel_df[numeric_cols[i], 'sem'] <- get_sem(numeric_cols[i])
  rel_df[numeric_cols[i], 'var_subs'] <- get_var_breakdown(numeric_cols[i])$subs
  rel_df[numeric_cols[i], 'var_ind'] <- get_var_breakdown(numeric_cols[i])$ind
  rel_df[numeric_cols[i], 'var_resid'] <- get_var_breakdown(numeric_cols[i])$resid
}

rel_df$dv = row.names(rel_df)
row.names(rel_df) = seq(1:nrow(rel_df))
rel_df$task = 'task'
rel_df[grep('survey', rel_df$dv), 'task'] = 'survey'
rel_df[grep('holt', rel_df$dv), 'task'] = "task"
rel_df = rel_df %>%
  select(dv, task, spearman, icc, pearson, eta_sq, sem, var_subs, var_ind, var_resid)
# row.names(rel_df) = NULL

Though we are primarily reporting ICC’s as our metric of reliability the results don’t change depending on the metric chosen. Here we plot point estimates of three different reliability metrics against each other (ICC, Pearson, Spearman). The bootstrapped version is essentially the same but the plots are busier due to more datapoints.

p1 = rel_df %>%
  ggplot(aes(spearman, icc, col=task))+
  geom_point()+
  theme_bw()+
  theme(legend.title = element_blank(),
        legend.position = "none")+
  geom_abline(intercept = 0, slope=1)

p2 = rel_df %>%
  ggplot(aes(pearson, icc, col=task))+
  geom_point()+
  theme_bw()+
  theme(legend.title = element_blank(),
        legend.position = "none")+
  geom_abline(intercept = 0, slope=1)

p3 = rel_df %>%
  ggplot(aes(pearson, spearman, col=task))+
  geom_point()+
  theme_bw()+
  theme(legend.title = element_blank(),
        legend.position = "none")+
  geom_abline(intercept = 0, slope=1)

grid.arrange(p1, p2, p3, nrow=1)

ggsave('Metric_Scatterplots.jpg', plot = grid.arrange(p1, p2, p3, nrow=1), device = "jpeg", path = "/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/output/figures/", width = 12, height = 4, units = "in", limitsize = FALSE)

Note: Some variables have <0 ICC’s. This would be the case if the \(MS_{error}\)>\(MS_{between}\). Data for these variables have no relationship between the two time points.

Summary of all measure reliabilities

Summarized bootstrapped reliabilities

boot_df <- read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/bootstrap_merged.csv')

boot_df = boot_df %>%
  drop_na() %>%
  mutate(icc = as.numeric(as.character(icc)),
         spearman = as.numeric(as.character(spearman)),
         eta_sq = as.numeric(as.character(eta_sq)),
         sem = as.numeric(as.character(sem))) 

boot_df = boot_df[boot_df$dv %in% retest_report_vars,]

# retest_report_vars[which(retest_report_vars %in% boot_df$dv==FALSE)]

boot_df %>%
  group_by(dv) %>%
  summarise(icc_median = quantile(icc, probs = 0.5),
            icc_2.5 = quantile(icc, probs = 0.025),
            icc_97.5 = quantile(icc, probs = 0.975),
            spearman_median = quantile(spearman, probs = 0.5),
            spearman_2.5 = quantile(spearman, probs = 0.025),
            spearman_97.5 = quantile(spearman, probs = 0.975)) %>%
  datatable() %>%
  formatRound(columns=c('icc_median', 'icc_2.5', 'icc_97.5', 'spearman_median', 'spearman_2.5', 'spearman_97.5'), digits=3)
# Df wrangling for plotting
tmp = measure_labels %>%
  mutate(dv = as.character(dv)) %>%
  left_join(boot_df[,c("dv", "icc", "spearman")], by = 'dv') 

tmp = tmp %>%
  separate(dv, c("task_group", "var"), sep="\\.",remove=FALSE,extra="merge") %>%
  mutate(task_group = factor(task_group, levels = task_group[order(task)])) %>%
  separate(var, c("var"), sep="\\.",remove=TRUE,extra="drop") %>%
  mutate(task_group = gsub("_", " ", task_group),
         var = gsub("_", " ", var)) %>%
  arrange(task_group, var)

tmp = tmp %>%
  left_join(rel_df[,c("dv", "icc")], by = "dv") %>%
  rename(icc = icc.x, point_est = icc.y)

#Manual correction
tmp = tmp %>%
  mutate(task = ifelse(task_group == 'holt laury survey', "task", as.character(task))) %>%
  mutate(task_group = ifelse(task_group == "psychological refractory period two choices", "psychological refractory period", ifelse(task_group == "angling risk task always sunny", "angling risk task",task_group))) %>%
  mutate(task_group = gsub("survey", "", task_group))

Variable level summary of bootstrapped reliabilities.

p4 <- tmp %>%
  filter(task == 'task',
         raw_fit == 'raw') %>%
ggplot(aes(y = var, x = icc)) + 
  geom_point(color = '#00BFC4')+
  geom_point(aes(y = var, x = point_est), color = "black")+
  facet_grid(task_group~., switch = "y", scales = "free_y", space = "free_y", labeller = label_wrap_gen(width=20)) +
  theme(panel.spacing = unit(0.75, "lines"), 
        strip.placement = "outside",
        strip.text.y = element_text(angle=180, size=36),
        axis.text.y = element_text(size=20),
        panel.background = element_rect(fill = NA),
        panel.grid.major = element_line(colour = "grey80")) + 
  xlab("")+
  ylab("")+
  scale_x_continuous(limits = c(-0.25,1), breaks=c(-0.25, 0, 0.25, 0.5, 0.75, 1))+
  scale_y_discrete(labels = function(x) str_wrap(x, width = 10))+
  geom_vline(xintercept = 0, color = "red", size = 1)

p5 <- tmp %>%
  filter(task == 'survey') %>%
ggplot(aes(y = var, x = icc)) + 
  geom_point(color = '#F8766D')+
  geom_point(aes(y = var, x = point_est), color = "black")+
  facet_grid(task_group~., switch = "y", scales = "free_y", space = "free_y", labeller = label_wrap_gen(width=20)) +
  theme(panel.spacing = unit(0.75, "lines"), 
        strip.placement = "outside",
        strip.text.y = element_text(angle=180, size=36),
        axis.text.y = element_text(size=20),
        panel.background = element_rect(fill = NA),
        panel.grid.major = element_line(colour = "grey80")) + 
  xlab("")+
  ylab("")+
  scale_x_continuous(limits = c(-0.25,1), breaks=c(-0.25, 0, 0.25, 0.5, 0.75, 1))+
  scale_y_discrete(labels = function(x) str_wrap(x, width = 10))+
  geom_vline(xintercept = 0, color = "red", size = 1)
  
p6 <- arrangeGrob(p4, p5,nrow=1)

ggsave('Bootstrap_Raw_Var_Plot.jpg', plot = p6, device = "jpeg", path = "/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/output/figures/", width = 36, height = 72, units = "in", limitsize = FALSE, dpi=50)

rm(p4, p5, p6)

p4_t <- tmp %>%
  filter(task == 'task') %>%
ggplot(aes(x = factor(task_group, levels=rev(unique(task_group))), y = icc)) + 
  geom_violin(fill='#00BFC4')+
  theme_bw() + 
  theme(axis.text.y = element_text(size=30))+
  xlab("")+
  ylab("")+
  scale_y_continuous(limits = c(-0.25,1), breaks=c(-0.25, 0, 0.25, 0.5, 0.75, 1))+
  scale_x_discrete(labels = function(x) str_wrap(x, width = 15))+
  geom_hline(yintercept = 0, color = "red", size = 1)+
  coord_flip()

p5_t <- tmp %>%
  filter(task == 'survey') %>%
ggplot(aes(x = factor(task_group, levels=rev(unique(task_group))), y = icc)) + 
  geom_violin(fill='#F8766D')+
  theme_bw() + 
  theme(axis.text.y = element_text(size=43))+
  xlab("")+
  ylab("")+
  scale_y_continuous(limits = c(-0.25,1), breaks=c(-0.25, 0, 0.25, 0.5, 0.75, 1))+
  scale_x_discrete(labels = function(x) str_wrap(x, width = 10))+
  geom_hline(yintercept = 0, color = "red", size = 1)+
  coord_flip()
  
p6_t <- arrangeGrob(p4_t, p5_t,nrow=1)

ggsave('Bootstrap_Poster_Plot_t.jpg', plot = p6_t, device = "jpeg", path = "../output/figures/", width = 27, height = 48, units = "in", limitsize = FALSE)

Survey vs Tasks

Comparison of survey measures to cognitive task measures in the bootstrapped results. Multilevel model with random intercepts for each measure and fixed effect of survey versus cognitive measure.

boot_df = boot_df %>%
    mutate(task = ifelse(grepl("survey",dv), "survey","task"),
           task = ifelse(grepl("holt",dv), "task", task))

boot_df %>%
  group_by(task) %>%
  summarise(icc_median = quantile(icc, probs = 0.5),
            icc_2.5 = quantile(icc, probs = 0.025),
            icc_97.5 = quantile(icc, probs = 0.975),
            spearman_median = quantile(spearman, probs = 0.5),
            spearman_2.5 = quantile(spearman, probs = 0.025),
            spearman_97.5 = quantile(spearman, probs = 0.975),
            num_vars = n()/1000) %>%
  datatable() %>%
  formatRound(columns=c('icc_median', 'icc_2.5', 'icc_97.5', 'spearman_median', 'spearman_2.5', 'spearman_97.5'), digits=3)
summary(lmerTest::lmer(icc ~  task + (1|dv), boot_df))
Linear mixed model fit by REML t-tests use Satterthwaite approximations
  to degrees of freedom [lmerMod]
Formula: icc ~ task + (1 | dv)
   Data: boot_df

REML criterion at convergence: -917682

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-11.241  -0.402   0.024   0.461   7.246 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept) 0.05214  0.2283  
 Residual             0.00683  0.0827  
Number of obs: 429000, groups:  dv, 429

Fixed effects:
            Estimate Std. Error       df t value Pr(>|t|)    
(Intercept)   0.8722     0.0265 428.0000    32.9   <2e-16 ***
tasktask     -0.3859     0.0292 428.0000   -13.2   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
         (Intr)
tasktask -0.910
boot_df %>%
  ggplot(aes(icc, fill = task))+
  geom_histogram(alpha=0.5, position='identity')+
  theme_bw()+
  theme(legend.title = element_blank())+
  xlab("ICC")

ggsave('Hist_Boot_Rel.jpg', device = "jpeg", path = "/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/output/figures/", width = 6, height = 4, units = "in", limitsize = FALSE, dpi = 72)

Variance breakdown

The quantiative explanation for the difference in reliability estimates between surveys and tasks, as recently detailed by Hedge et al. (2017), lies in the difference in sources of variance between these measures. This is because reliability is estimated as a ratio of these sources variance to each other. Specifically, the ICC is calculated as the ratio of variance between subjects variance to all sources of variance. Thus, measures with high between subjects variance would have high test-retest reliability. Intuitively, measures with high between subjects variance are also better suited for individual difference analyses as they would capture the differences between the subjects in a sample.

Here we first plot the percentage of variance explained by the three sources of variance for the point estimates of measure reliabilities. The plot only includes raw measures (no DDM parameters) and the measures are ranked by percentage of between subject variability for each task/survey (i.e. the best to worst individual difference measure for each task/survey). Then we compare statistically whether the percentage of variance explained by these sources differ between tasks and surveys.

tmp = rel_df %>%
  mutate(var_subs_pct = var_subs/(var_subs+var_ind+var_resid)*100,
         var_ind_pct = var_ind/(var_subs+var_ind+var_resid)*100, 
         var_resid_pct = var_resid/(var_subs+var_ind+var_resid)*100) %>%
  select(dv, task, var_subs_pct, var_ind_pct, var_resid_pct) %>%
  mutate(dv = factor(dv, levels = dv[order(task)])) %>%
  separate(dv, c("task_group", "var"), sep="\\.",remove=FALSE,extra="merge") %>%
  mutate(task_group = factor(task_group, levels = task_group[order(task)])) %>%
  arrange(task_group, var_subs_pct) %>%
  mutate(rank = row_number()) %>%
  arrange(task, task_group, rank) %>%
  gather(key, value, -dv, -task_group, -var, -task, -rank) %>%
  ungroup()%>%
  mutate(task_group = gsub("_", " ", task_group),
         var = gsub("_", " ", var)) %>%
  mutate(task_group = ifelse(task_group == "psychological refractory period two choices", "psychological refractory period", ifelse(task_group == "angling risk task always sunny", "angling risk task",task_group))) %>%
  mutate(task_group = gsub("survey", "", task_group)) %>%
  filter(task=="task",
         !grepl("EZ|hddm", dv))%>%
  arrange(task_group, rank)
labels = tmp %>%
  distinct(dv, .keep_all=T)

p1 <- tmp %>%
  ggplot(aes(x=factor(rank), y=value, fill=factor(key, levels = c("var_resid_pct", "var_ind_pct", "var_subs_pct"))))+
  geom_bar(stat='identity', alpha = 0.75, color='#00BFC4')+
  scale_x_discrete(breaks = labels$rank,
                       labels = labels$var)+
  coord_flip()+
  facet_grid(task_group~., switch = "y", scales = "free_y", space = "free_y") +
  theme(panel.spacing = unit(0.5, "lines"), 
        strip.placement = "outside",
        strip.text.y = element_text(angle=180),
        panel.background = element_rect(fill = NA),
        panel.grid.major = element_line(colour = "grey85"),
        legend.position = 'bottom')+
  theme(legend.title = element_blank())+
  scale_fill_manual(breaks = c("var_subs_pct", "var_ind_pct", "var_resid_pct"),
                      labels = c("Variance between individuals",
                                 "Variance between sessions",
                                 "Error variance"),
                  values=c("grey65", "grey45", "grey25"))+
  ylab("")+
  xlab("")

tmp = rel_df %>%
  mutate(var_subs_pct = var_subs/(var_subs+var_ind+var_resid)*100,
         var_ind_pct = var_ind/(var_subs+var_ind+var_resid)*100, 
         var_resid_pct = var_resid/(var_subs+var_ind+var_resid)*100) %>%
  select(dv, task, var_subs_pct, var_ind_pct, var_resid_pct) %>%
  mutate(dv = factor(dv, levels = dv[order(task)])) %>%
  separate(dv, c("task_group", "var"), sep="\\.",remove=FALSE,extra="merge") %>%
  mutate(task_group = factor(task_group, levels = task_group[order(task)])) %>%
  arrange(task_group, var_subs_pct) %>%
  mutate(rank = row_number()) %>%
  arrange(task, task_group, rank) %>%
  gather(key, value, -dv, -task_group, -var, -task, -rank) %>%
  ungroup()%>%
  mutate(task_group = gsub("_", " ", task_group),
         var = gsub("_", " ", var)) %>%
  mutate(task_group = ifelse(task_group == "psychological refractory period two choices", "psychological refractory period", ifelse(task_group == "angling risk task always sunny", "angling risk task",task_group))) %>%
  mutate(task_group = gsub("survey", "", task_group)) %>%
  filter(task=="survey")%>%
  arrange(task_group, rank)
labels = tmp %>%
  distinct(dv, .keep_all=T)

p2 <- tmp %>%
  ggplot(aes(x=factor(rank), y=value, fill=factor(key, levels = c("var_resid_pct", "var_ind_pct", "var_subs_pct"))))+
  geom_bar(stat='identity', alpha = 0.75)+
  geom_bar(stat='identity', color='#F8766D', show.legend=FALSE)+
  scale_x_discrete(breaks = labels$rank,
                       labels = labels$var)+
  coord_flip()+
  facet_grid(task_group~., switch = "y", scales = "free_y", space = "free_y") +
  theme(panel.spacing = unit(0.5, "lines"), 
        strip.placement = "outside",
        strip.text.y = element_text(angle=180),
        panel.background = element_rect(fill = NA),
        panel.grid.major = element_line(colour = "grey85"),
        legend.position = 'bottom')+
  theme(legend.title = element_blank())+
  scale_fill_manual(breaks = c("var_subs_pct", "var_ind_pct", "var_resid_pct"),
                      labels = c("Variance between individuals",
                                 "Variance between sessions",
                                 "Error variance"),
                  values=c("grey65", "grey45", "grey25"))+
  ylab("")+
  xlab("")

mylegend<-g_legend(p2)

p3 <- arrangeGrob(arrangeGrob(p1 +theme(legend.position="none"),
                         p2 + theme(legend.position="none"),
                         nrow=1),
             mylegend, nrow=2,heights=c(10, 1))

ggsave('Variance_Breakdown_Plot.jpg', plot = p3, device = "jpeg", path = "/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/output/figures", width = 24, height = 20, units = "in")
rm(tmp, labels)

Comparing types of variance for survey vs task measures: Survey measures have higher between subject variability

Note: This analysis includes DDM variables too.

tmp = boot_df %>%
  mutate(var_subs_pct = var_subs/(var_subs+var_ind+var_resid)*100,
         var_ind_pct = var_ind/(var_subs+var_ind+var_resid)*100, 
         var_resid_pct = var_resid/(var_subs+var_ind+var_resid)*100) %>%
  select(dv, task, var_subs_pct, var_ind_pct, var_resid_pct) %>%
  gather(key, value, -dv, -task) 

summary(lmer(value~key*task+(1|dv),tmp))
Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, : Model is nearly unidentifiable: very large eigenvalue
 - Rescale variables?
Linear mixed model fit by REML ['lmerMod']
Formula: value ~ key * task + (1 | dv)
   Data: tmp

REML criterion at convergence: 10765111

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-3.422 -0.668 -0.085  0.608  4.224 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept)   0       0.0    
 Residual             251      15.9    
Number of obs: 1287000, groups:  dv, 429

Fixed effects:
                           Estimate Std. Error t value
(Intercept)                9.84e+00   5.83e-02     169
keyvar_resid_pct          -7.05e-05   8.24e-02       0
keyvar_subs_pct            7.05e+01   8.24e-02     855
tasktask                   1.34e+01   6.41e-02     210
keyvar_resid_pct:tasktask  1.26e+00   9.06e-02      14
keyvar_subs_pct:tasktask  -4.15e+01   9.06e-02    -458

Correlation of Fixed Effects:
            (Intr) kyvr_r_ kyvr_s_ tsktsk kyvr_r_:
kyvr_rsd_pc -0.707                                
kyvr_sbs_pc -0.707  0.500                         
tasktask    -0.910  0.643   0.643                 
kyvr_rsd_p:  0.643 -0.910  -0.455  -0.707         
kyvr_sbs_p:  0.643 -0.455  -0.910  -0.707  0.500  
convergence code: 0
Model is nearly unidentifiable: very large eigenvalue
 - Rescale variables?
aggregate(value ~task+key, FUN=mean, data=tmp)
tmp%>%
  group_by(task, key) %>%
  summarise(median = median(value),
            sd = sd(value))

Summarizing for clearer presentation. This grap is currently using the bootstrapped reliabilities and is therefore messier than if just using the point estimates.

tmp %>%
  group_by(task, key) %>%
  ggplot(aes(factor(task, levels=c("task","survey"), labels=c("Task", "Survey")), value, fill=key, color=task))+
  geom_boxplot()+
  theme_bw()+
  theme(legend.title = element_blank())+
  scale_fill_manual(breaks = c("var_subs_pct", "var_ind_pct", "var_resid_pct"),
                    labels = c("Variance between individuals",
                               "Variance between sessions",
                               "Error variance"),
                    values=c("grey65", "grey45", "grey25"))+
  scale_color_discrete(guide = FALSE)+
  xlab("")+
  ylab("Percent")

ggsave('Variance_Breakdown_Plot_Summary.jpg', device = "jpeg", path = "/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/output/figures", width = 10, height = 5, units = "in")

Task Reliabilities

Here we summarize the results on a task level to make it more digestable and easier to make contact with the literature.

We reduce the list of task measures to a list of one per task by averaging only the raw measures from all the trials in a task. We chose to reduce the information in this manner to avoid any bias stemming from differential amount of interest and procedures applied to certain tasks over others (e.g. a task can have over 10 measures because it has multiple conditions and we have chosen to fit DDM’s for specific conditions while another might only have 2 due to our relative inexperience and lack of interest in it). We check whether the number of trials in a task has a significant effect on these average reliabilities of raw measures as well.

We filter out the DDM parameters and measures for specific contrasts. Note that this does leave some tasks with measures that are model fits and/or for specific conditions (because at least the current datasets do not include measures that are based on all the trials and are raw though I could dive in to variables_exhaustive for such measures. For example the average relialibility for Kirby is based on three discount rates for specific conditions.). Here’s the order of tasks by mean reliability sorted for ICC and then Spearman’s \(\rho\).

tmp = measure_labels %>%
  mutate(dv = as.character(dv)) %>%
  filter(task == 'task') %>%
  left_join(boot_df[,c("dv", "icc", "spearman")], by = 'dv') %>%
  filter(overall_difference != 'difference' & raw_fit %in% c('EZ', 'hddm') == FALSE)%>%
  separate(dv, c('task_name', 'extra_1', 'extra_2'), sep = '\\.',remove=FALSE) %>%
  select(-extra_1, -extra_2) %>%
  group_by(task_name) %>%
  summarise(median_icc = median(icc),
            median_spearman = median(spearman),
            min_icc = min(icc),
            max_icc = max(icc),
            min_spearman = min(spearman),
            max_spearman = max(spearman),
            num_measures = n(),
            num_trials = unique(num_all_trials))%>%
  arrange(-median_icc, -median_spearman)

tmp %>%
  datatable() %>%
  formatRound(columns=c('median_spearman', 'median_icc',
                        'min_spearman', 'min_icc',
                        'max_spearman', 'max_icc'), digits=3)

Number of trials

Does number of items in a task have a significant effect on the average ICC of (mostly) raw measures for all trials from a task? No. (no effect on Spearman either)

tmp = measure_labels %>%
  mutate(dv = as.character(dv)) %>%
  filter(task == 'task') %>%
  # left_join(rel_df[,c("dv", "spearman","icc")], by='dv') %>%
  left_join(boot_df[,c("dv", "spearman","icc")], by='dv') %>%
  filter(overall_difference != 'difference' & raw_fit %in% c('EZ', 'hddm') == FALSE)%>%
  separate(dv, c('task_name', 'extra_1', 'extra_2'), sep = '\\.',remove=FALSE) %>%
  select(-extra_1, -extra_2)

# summary(lm(icc ~ num_all_trials, data = tmp))
summary(lmer(icc ~ num_all_trials + (1|dv), data = tmp))
Linear mixed model fit by REML ['lmerMod']
Formula: icc ~ num_all_trials + (1 | dv)
   Data: tmp

REML criterion at convergence: -380286

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-11.439  -0.462   0.037   0.523   7.564 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept) 0.04299  0.2073  
 Residual             0.00555  0.0745  
Number of obs: 162000, groups:  dv, 162

Fixed effects:
                 Estimate Std. Error t value
(Intercept)     0.5922642  0.0231072   25.63
num_all_trials -0.0000518  0.0001206   -0.43

Correlation of Fixed Effects:
            (Intr)
num_ll_trls -0.709
measure_labels %>%
  mutate(dv = as.character(dv)) %>%
  filter(task == 'task') %>%
  # left_join(rel_df[,c("dv", "spearman","icc")], by='dv') %>%
  left_join(boot_df[,c("dv", "spearman","icc")], by='dv') %>%
  filter(overall_difference != 'difference' & raw_fit %in% c('EZ', 'hddm') == FALSE)%>%
  separate(dv, c('task_name', 'extra_1', 'extra_2'), sep = '\\.',remove=FALSE) %>%
  select(-extra_1, -extra_2) %>%
  ggplot(aes(num_all_trials, icc))+
  geom_point()+
  geom_smooth(method="lm")+
  theme_bw()+
  xlab("Number of trials")+
  ylab("ICC")

Trial number dependence intrameasure

The above analysis was looking at the effect of number of trials across tasks. But some tasks might be bad for individual difference measurement regardless of how many trials there are in them whereas for others fewer trials might be yielding a sufficiently reliable measure.

For tasks for which dependent variables are estimated using many trials one can ask: Does the same measure get less reliable if fewer trials are used to estimate its reliability?

This won’t make sense for all tasks. For example to estimate a risk aversion parameter you need all trials for Holt and Laury. For Kirby and Bickel you have specific conditions looking at fewer trials. The Cognitive Reflection Task might be more appropriate to analyze each item seaprately. The writing task does not have trial numbers. For all others it might be interesting to investigate.

That said this kind of analysis seems too in the weeds for a paper that is trying to give a global sense of the differences between self-regulation measures in their suitablity for individual difference analyses based on their stability across time. Such analyses would provide a detailed examination of how to extract the most reliable/best individual difference measure from tasks with a set of mediocre variables to begin with. So I am choosing to ignore this for now but this can be revisited.

Raw vs DDM

Checking DDM results in the bootstrapped estimates. Variables using all trials are significantly more reliable compared to difference scores. Raw measures don’t differ from DDM parameters. Which DDM is better depends on whether all trials are used.

tmp = measure_labels %>%
  mutate(dv = as.character(dv)) %>%
  filter(ddm_task == 1, 
         overall_difference != "condition") %>%
  drop_na() %>%
  left_join(boot_df[,c("dv", "icc", "spearman")], by = 'dv')

tmp %>%
  group_by(overall_difference, raw_fit, rt_acc) %>%
  summarise(icc_median = quantile(icc, probs = 0.5),
            icc_2.5 = quantile(icc, probs = 0.025),
            icc_97.5 = quantile(icc, probs = 0.975),
            spearman_median = quantile(spearman, probs = 0.5),
            spearman_2.5 = quantile(spearman, probs = 0.025),
            spearman_97.5 = quantile(spearman, probs = 0.975),
            num_vars = n()/1000) %>%
  datatable() %>%
  formatRound(columns=c('icc_median', 'icc_2.5', 'icc_97.5', 'spearman_median', 'spearman_2.5', 'spearman_97.5'), digits=3)
summary(lmerTest::lmer(icc ~ overall_difference*raw_fit + (1|dv) ,tmp))
Linear mixed model fit by REML t-tests use Satterthwaite approximations
  to degrees of freedom [lmerMod]
Formula: icc ~ overall_difference * raw_fit + (1 | dv)
   Data: tmp

REML criterion at convergence: -401006

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-9.633 -0.465  0.039  0.513  5.470 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept) 0.0326   0.1806  
 Residual             0.0093   0.0965  
Number of obs: 219000, groups:  dv, 219

Fixed effects:
                                      Estimate Std. Error       df t value
(Intercept)                             0.1986     0.0261 213.8000    7.62
overall_differenceoverall               0.4507     0.0382 213.8000   11.81
raw_fithddm                             0.1268     0.0521 213.8000    2.43
raw_fitraw                              0.0761     0.0389 213.8000    1.96
overall_differenceoverall:raw_fithddm  -0.2198     0.0654 213.8000   -3.36
overall_differenceoverall:raw_fitraw   -0.0469     0.0575 213.8000   -0.82
                                      Pr(>|t|)    
(Intercept)                            8.2e-13 ***
overall_differenceoverall              < 2e-16 ***
raw_fithddm                            0.01586 *  
raw_fitraw                             0.05181 .  
overall_differenceoverall:raw_fithddm  0.00091 ***
overall_differenceoverall:raw_fitraw   0.41556    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
                        (Intr) ovrll_ rw_fth rw_ftr
ovrll_dffrn             -0.683                     
raw_fithddm             -0.500  0.342              
raw_fitraw              -0.670  0.457  0.335       
ovrll_dffrncvrll:rw_fth  0.399 -0.584 -0.798 -0.267
ovrll_dffrncvrll:rw_ftr  0.453 -0.663 -0.226 -0.677
                        ovrll_dffrncvrll:rw_fth
ovrll_dffrn                                    
raw_fithddm                                    
raw_fitraw                                     
ovrll_dffrncvrll:rw_fth                        
ovrll_dffrncvrll:rw_ftr  0.387                 
tmp %>%
  ggplot(aes(factor(raw_fit, levels = c("raw", "EZ", "hddm"), labels=c("Raw", "EZ-diffusion", "Hierarchical diffusion")), icc, fill=factor(rt_acc, levels = c("rt","accuracy","other", "drift rate", "threshold", "non-decision"), labels=c("Response Time", "Accuracy", "Other","Drift Rate", "Threshold", "Non-decision"))))+
  geom_boxplot()+
  facet_wrap(~factor(overall_difference, levels=c("overall", "difference"), labels=c("Overall", "Difference")))+
  theme_bw()+
  ylab("ICC")+
  xlab("")+
  theme(legend.title = element_blank())

ggsave('Bootstrap_DDM_Comp.jpg', device = "jpeg", path = "/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/output/figures/", width = 24, height = 6, units = "in", limitsize = FALSE)

DDM Variance breakdown

What does the variance breakdown look like for DDM variables separately?

tmp = rel_df %>%
  mutate(var_subs_pct = var_subs/(var_subs+var_ind+var_resid)*100,
         var_ind_pct = var_ind/(var_subs+var_ind+var_resid)*100, 
         var_resid_pct = var_resid/(var_subs+var_ind+var_resid)*100) %>%
  select(dv, task, var_subs_pct, var_ind_pct, var_resid_pct) %>%
  mutate(dv = factor(dv, levels = dv[order(task)])) %>%
  separate(dv, c("task_group", "var"), sep="\\.",remove=FALSE,extra="merge") %>%
  mutate(task_group = factor(task_group, levels = task_group[order(task)])) %>%
  arrange(task_group, var_subs_pct) %>%
  mutate(rank = row_number()) %>%
  arrange(task, task_group, rank) %>%
  gather(key, value, -dv, -task_group, -var, -task, -rank) %>%
  ungroup()%>%
  mutate(task_group = gsub("_", " ", task_group),
         var = gsub("_", " ", var)) %>%
  mutate(task_group = ifelse(task_group == "psychological refractory period two choices", "psychological refractory period", ifelse(task_group == "angling risk task always sunny", "angling risk task",task_group))) %>%
  mutate(task_group = gsub("survey", "", task_group)) %>%
  filter(task=="task",
         grepl("EZ|hddm", dv))%>%
  arrange(task_group, rank)
labels = tmp %>%
  distinct(dv, .keep_all=T)

p1 <- tmp %>%
  ggplot(aes(x=factor(rank), y=value, fill=factor(key, levels = c("var_resid_pct", "var_ind_pct", "var_subs_pct"))))+
  geom_bar(stat='identity', alpha = 0.75, color='#00BFC4')+
  scale_x_discrete(breaks = labels$rank,
                       labels = labels$var)+
  coord_flip()+
  facet_grid(task_group~., switch = "y", scales = "free_y", space = "free_y") +
  theme(panel.spacing = unit(0.5, "lines"), 
        strip.placement = "outside",
        strip.text.y = element_text(angle=180),
        panel.background = element_rect(fill = NA),
        panel.grid.major = element_line(colour = "grey85"),
        legend.position = 'bottom')+
  theme(legend.title = element_blank())+
  scale_fill_manual(breaks = c("var_subs_pct", "var_ind_pct", "var_resid_pct"),
                      labels = c("Variance between individuals",
                                 "Variance between sessions",
                                 "Error variance"),
                  values=c("grey65", "grey45", "grey25"))+
  ylab("")+
  xlab("")

ggsave('Variance_Breakdown_Plot_DDM.jpg', plot = p1, device = "jpeg", path = "/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/output/figures", width = 12, height = 20, units = "in")

Summarizing it by raw vs fit and for each parameter

tmp = measure_labels %>%
  mutate(dv = as.character(dv)) %>%
  filter(ddm_task == 1, 
         overall_difference != "condition") %>%
  drop_na() %>%
  left_join(boot_df[,c("dv", "icc", "var_subs", "var_ind", "var_resid")], by = 'dv') %>%
  mutate(var_subs_pct = (var_subs/(var_subs+var_ind+var_resid))*100,
         var_ind_pct= (var_ind/(var_subs+var_ind+var_resid))*100,
         var_resid_pct = (var_resid/(var_subs+var_ind+var_resid))*100) %>%
  select(-task, -ddm_task, -num_all_trials, -var_subs, -var_ind, -var_resid) %>%
  gather(key, value, -dv, -overall_difference, -raw_fit, -rt_acc, -icc)

tmp %>%
  ggplot(aes(factor(raw_fit, levels = c("raw", "EZ", "hddm"), labels=c("Raw", "EZ-diffusion", "Hierarchical diffusion")), value, fill=factor(rt_acc, levels = c("rt","accuracy","other", "drift rate", "threshold", "non-decision"), labels=c("Response Time", "Accuracy", "Other","Drift Rate", "Threshold", "Non-decision"))))+
  geom_boxplot()+
  facet_grid(factor(key, levels = c("var_subs_pct", "var_ind_pct", "var_resid_pct"), labels=c("Variance between subjects", "Variance between individuals", "Error variance"))~factor(overall_difference, levels=c("overall", "difference"), labels=c("Overall", "Difference")))+
  theme_bw()+
  ylab("% of total variance")+
  xlab("")+
  theme(legend.title = element_blank())

ggsave('Variance_Breakdown_Plot_DDM_summary.jpg', device = "jpeg", path = "/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/output/figures", width = 10, height = 8, units = "in")

Do these differ statistically?

The plot does not suggest so but this model is giving a warning and very high t values. How else should I be checking for differences between these distributions?

summary(lmer(value~key*overall_difference*raw_fit+(1|dv), tmp))
Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, : Model is nearly unidentifiable: very large eigenvalue
 - Rescale variables?
Linear mixed model fit by REML ['lmerMod']
Formula: value ~ key * overall_difference * raw_fit + (1 | dv)
   Data: tmp

REML criterion at convergence: 5546086

Scaled residuals: 
   Min     1Q Median     3Q    Max 
-3.134 -0.708 -0.035  0.629  4.015 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept)   0       0.0    
 Residual             271      16.5    
Number of obs: 657000, groups:  dv, 219

Fixed effects:
                                                       Estimate Std. Error
(Intercept)                                             21.6705     0.0752
keyvar_resid_pct                                        12.2911     0.1063
keyvar_subs_pct                                         22.6975     0.1063
overall_differenceoverall                                5.7338     0.1101
raw_fithddm                                             10.3546     0.1504
raw_fitraw                                               2.3821     0.1123
keyvar_resid_pct:overall_differenceoverall             -21.2319     0.1557
keyvar_subs_pct:overall_differenceoverall                4.0303     0.1557
keyvar_resid_pct:raw_fithddm                           -17.6249     0.2127
keyvar_subs_pct:raw_fithddm                            -13.4388     0.2127
keyvar_resid_pct:raw_fitraw                             -5.1278     0.1588
keyvar_subs_pct:raw_fitraw                              -2.0184     0.1588
overall_differenceoverall:raw_fithddm                  -10.5695     0.1885
overall_differenceoverall:raw_fitraw                    -5.1719     0.1660
keyvar_resid_pct:overall_differenceoverall:raw_fithddm  21.0070     0.2666
keyvar_subs_pct:overall_differenceoverall:raw_fithddm   10.7014     0.2666
keyvar_resid_pct:overall_differenceoverall:raw_fitraw    6.6271     0.2348
keyvar_subs_pct:overall_differenceoverall:raw_fitraw     8.8886     0.2348
                                                       t value
(Intercept)                                              288.2
keyvar_resid_pct                                         115.6
keyvar_subs_pct                                          213.4
overall_differenceoverall                                 52.1
raw_fithddm                                               68.9
raw_fitraw                                                21.2
keyvar_resid_pct:overall_differenceoverall              -136.4
keyvar_subs_pct:overall_differenceoverall                 25.9
keyvar_resid_pct:raw_fithddm                             -82.9
keyvar_subs_pct:raw_fithddm                              -63.2
keyvar_resid_pct:raw_fitraw                              -32.3
keyvar_subs_pct:raw_fitraw                               -12.7
overall_differenceoverall:raw_fithddm                    -56.1
overall_differenceoverall:raw_fitraw                     -31.2
keyvar_resid_pct:overall_differenceoverall:raw_fithddm    78.8
keyvar_subs_pct:overall_differenceoverall:raw_fithddm     40.1
keyvar_resid_pct:overall_differenceoverall:raw_fitraw     28.2
keyvar_subs_pct:overall_differenceoverall:raw_fitraw      37.9

Correlation matrix not shown by default, as p = 18 > 12.
Use print(x, correlation=TRUE)  or
     vcov(x)     if you need it
convergence code: 0
Model is nearly unidentifiable: very large eigenvalue
 - Rescale variables?

Change in parameter values depending on sample

How much do parameter values change depending on whether the model was fit using the whole sample vs only the retest sample. Each point in these graphs is a subject’s parameter estimates. There is almost no change for any of the EZ parameters (though shouldn’t this have been 0?). For the HDDM parameters most of the changes are happening for drift rates but they don’t appear to be systematically higher or lower.

I’m not entirely sure what to make of this. A systematic change would have meant that the ranking remained the same regardless of the sample size. When the change is non-systematic in this way then a given subject that has high higher drift rates than most of the people in the full sample can appear to have lower drift rates than the same people when fit on the retest sample only. (note that a t-test is not significant)

Of course these parameter estimates themselves are not very interpretable in their ‘goodness’ as they don’t reflect anything about model fits. What is the measure of fits here? The variance of the posterior?

hddm_fullfits <- test_data_full_sample_hddm[,names(test_data_full_sample_hddm) %in% names(hddm_refits)]

hddm_fullfits = hddm_fullfits %>%
  gather(dv, value, -sub_id)

hddm_refits %>%
  gather(dv, value, -sub_id) %>%
  left_join(hddm_fullfits, by = c("sub_id", "dv")) %>%
  rename(fullfit = value.y, refit = value.x) %>%
  left_join(measure_labels[,c("dv", "raw_fit", "rt_acc")], by="dv") %>%
  filter(rt_acc %in% c("drift rate","non-decision", "threshold")) %>%
  ggplot(aes(fullfit, refit))+
  geom_point(aes(color=rt_acc))+
  facet_wrap(~raw_fit)+
  theme_bw()+
  geom_abline(slope=1, intercept=0)+
  xlab("Fit on full sample")+
  ylab("Fit on retest sample")+
  theme(legend.title = element_blank())

Parameter reliability depending on sample size

There doesn’t seem to be an effect looking at the graph but the multilevel model seems to show a very significant but tiny effect.

tmp <- read.csv('/Users/zeynepenkavi/Dropbox/PoldrackLab/SRO_Retest_Analyses/input/all_ddm_sample_size_summary.csv')

ggplotly(tmp %>%
  select(dv, N, icc_median) %>%
  left_join(measure_labels[,c("dv", "raw_fit", "rt_acc")], by="dv") %>%
  ggplot(aes(N, icc_median, color=dv))+
  geom_line()+
  theme_bw()+
  theme(legend.position = 'none')+
  xlab("Sample Size")+
  ylab("Median ICC"))
summary(lmer(icc_median ~ N + (1|dv), tmp))
Linear mixed model fit by REML ['lmerMod']
Formula: icc_median ~ N + (1 | dv)
   Data: tmp

REML criterion at convergence: -9249

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-10.117  -0.231   0.014   0.215   6.584 

Random effects:
 Groups   Name        Variance Std.Dev.
 dv       (Intercept) 0.071491 0.2674  
 Residual             0.000539 0.0232  
Number of obs: 2218, groups:  dv, 148

Fixed effects:
              Estimate Std. Error t value
(Intercept)  0.4448702  0.0220029   20.22
N           -0.0000909  0.0000114   -7.96

Correlation of Fixed Effects:
  (Intr)
N -0.042

Is the H in HDDM important?

TBD. Still need to figure out how to turn off the H.

Completion times

Subject level

Do people differ in how much their scores change depending on how many days it has been since they completed the initial battery?

Make data frame with difference between two scores for each measure for each subject. Since the scores for different measures are on different scales for comparability the difference scores are scaled (i.e. divided by their root mean square) but not centered so a value of 0 for the difference scores would indicate a lack of a difference between the scores of a subject.

t1_2_difference = data.frame()

for(i in 1:length(numeric_cols)){
  tmp = match_t1_t2(numeric_cols[i],format='wide')
  tmp = tmp %>% 
    # mutate(difference = scale(`2` - `1`))
  mutate(difference = scale(`2` - `1`, center=F))
  t1_2_difference = rbind(t1_2_difference, tmp)
}

t1_2_difference$difference = as.data.frame(t1_2_difference$difference)$V1

Add completion dates to this data frame.

t1_2_difference = merge(t1_2_difference, comp_dates[,c('sub_id', 'days_btw')], by='sub_id')

The effect of number of days in between in the full model where the difference scores are regressed on a fixed effect for measure and days between the two scores and random intercepts for each subject (Should this model include the interaction between the fixed effects?). Since there are over 400 measures the output of the full model is not presented here. Instead below are the coefficient for the fixed effect of days between completion times and its t value.

mod = lmer(difference ~ dv + days_btw + (1|sub_id), data = t1_2_difference)

data.frame(estimate=coef(summary(mod))["days_btw","Estimate"], tval=coef(summary(mod))["days_btw","t value"])

For visualization purposes I summarized the difference scores per person by looking at the average difference and plot that against the number of days between completion.

tmp = t1_2_difference %>%
  group_by(sub_id) %>%
  summarise(mean_diff = mean(difference, na.rm=T),
            days_btw = unique(days_btw))

tmp %>%
  ggplot(aes(days_btw, mean_diff))+
  geom_point()+
  theme_bw()+
  xlab("Days between completion")+
  ylab("Mean standardized difference between two time points")+
  geom_smooth(method="lm")

To confirm: the slope of this line is not significant. That is, there doesn’t seem to be a systematic difference between the two measurements depending on the number of days between the two measurements.

summary(lm(mean_diff ~ days_btw, data=tmp))

Call:
lm(formula = mean_diff ~ days_btw, data = tmp)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.30567 -0.06283  0.00471  0.06969  0.23471 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept) -0.059770   0.032602   -1.83    0.069 .
days_btw     0.000546   0.000276    1.98    0.050 *
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.0993 on 148 degrees of freedom
Multiple R-squared:  0.0258,    Adjusted R-squared:  0.0192 
F-statistic: 3.92 on 1 and 148 DF,  p-value: 0.0496

Task level

For each variable does the average difference between two time points vary by the average number of days between the two time points? No. The slopes of these lines or the interaction is not significant.

t1_2_difference <- t1_2_difference %>%
  separate(dv, c('task_name', 'extra_1', 'extra_2'), sep = '\\.',remove=FALSE) %>%
  select(-extra_1, -extra_2) %>% 
  mutate(task = ifelse(grepl("survey",dv), "survey","task"),
           task = ifelse(grepl("holt",dv), "task", task))

# summary(lmer(difference ~ days_btw + (task_name|sub_id), t1_2_difference))

t1_2_difference %>%
  mutate(task = ifelse(grepl("survey",dv), "survey","task"),
           task = ifelse(grepl("holt",dv), "task", task)) %>%
  group_by(dv) %>%
  summarise(mean_diff = mean(difference),
            mean_days_btw = mean(days_btw),
            task = unique(task)) %>%
  ggplot(aes(mean_days_btw, mean_diff, color=task))+
  geom_point()+
  theme_bw()+
  geom_smooth(method="lm")+
  xlab("Average days between completion")+
  ylab("Average difference between time points")+
  theme(legend.title = element_blank())

tmp = t1_2_difference %>%
  group_by(dv) %>%
  summarise(mean_diff = mean(difference),
            mean_days_btw = mean(days_btw),
            task = unique(task))

summary(lm(mean_diff ~ mean_days_btw*task, tmp))

Call:
lm(formula = mean_diff ~ mean_days_btw * task, data = tmp)

Residuals:
    Min      1Q  Median      3Q     Max 
-0.3866 -0.0735  0.0029  0.0747  0.3361 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)
(Intercept)              2.1270     5.7888    0.37     0.71
mean_days_btw           -0.0187     0.0506   -0.37     0.71
tasktask                -4.0722     5.8832   -0.69     0.49
mean_days_btw:tasktask   0.0358     0.0514    0.70     0.49

Residual standard error: 0.117 on 425 degrees of freedom
Multiple R-squared:  0.0164,    Adjusted R-squared:  0.00945 
F-statistic: 2.36 on 3 and 425 DF,  p-value: 0.0708

Learning effects

Is the t2 score higher for task variables? Plotting the average difference between time points (for all subjects) for each dependent variable coloring by task. More positive on the y-axis means more improvement. Didn’t want to summarize it at task level because not all measures might be things we’d expect learning effects on.

It’s hard to detect any meaningful global changes/improvements from this graph. It seems that for each task there might be some variables that have improved at t2 but whether these are menaingful learning effects should be determined based on the variable.

t1_2_difference %>%
  filter(task == "task") %>%
  group_by(dv) %>%
  summarise(mean_diff = mean(difference),
            task_name = unique(task_name)) %>%
  ggplot(aes(dv,mean_diff, color=task_name))+
  geom_point()+
  theme_bw()+
  theme(legend.position = "none",
        axis.text.x = element_blank())+
  xlab("Dependent variable")+
  ylab("Average difference between time points")

Transformation effects

All results reported above were for non-transformed dependent variables.

We could compare the reliability (point) estimates for meaningful variables that have been transformed in the full dataset and transformed the same way in the retest dataset as well.

test_data_tmp <- test_data
retest_data_tmp <- retest_data

test_data <- read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/t1_data/meaningful_variables_clean.csv')
test_data$X <- as.character(test_data$X)
names(test_data)[which(names(test_data) == 'X')] <-'sub_id' 
retest_data <- read.csv('/Users/zeynepenkavi/Documents/PoldrackLabLocal/Self_Regulation_Ontology/Data/Retest_09-27-2017/meaningful_variables_clean.csv')
retest_data$X <- as.character(retest_data$X)
names(retest_data)[which(names(retest_data) == 'X')] <-'sub_id'
retest_data = retest_data[retest_data$sub_id %in% test_data$sub_id,]
numeric_cols_mngfl = c()

for(i in 1:length(names(test_data))){
  if(is.numeric(test_data[,i]) & names(test_data)[i] %in% names(retest_data)){
    numeric_cols_mngfl <- c(numeric_cols_mngfl, names(test_data)[i])
  }
}

rel_df_mngfl <- data.frame(icc = rep(NA, length(numeric_cols_mngfl)))

row.names(rel_df_mngfl) <- numeric_cols_mngfl

for(i in 1:length(numeric_cols_mngfl)){
  rel_df_mngfl[numeric_cols_mngfl[i], 'icc'] <- get_icc(numeric_cols_mngfl[i])
}

rel_df_mngfl$dv = row.names(rel_df_mngfl)
row.names(rel_df_mngfl) = seq(1:nrow(rel_df_mngfl))
rel_df_mngfl$task = 'task'
rel_df_mngfl[grep('survey', rel_df_mngfl$dv), 'task'] = 'survey'
rel_df_mngfl[grep('holt', rel_df_mngfl$dv), 'task'] = "task"
rel_df_mngfl
ggplotly(rel_df_mngfl %>%
  filter(grepl("logTr", dv)) %>%
  mutate(dv = gsub(".ReflogTr", "", dv),
         dv = gsub(".logTr", "", dv)) %>%
  left_join(rel_df[,c("dv", "icc")], by="dv") %>%
  ggplot(aes(icc.x, icc.y, color=task, label=dv))+
  geom_point()+
  theme_bw()+
  xlab("Reliability for transformed variable")+
  ylab("Reliability for raw variable")+
  geom_abline(slope=1, intercept=0),
  label=dv)
LS0tCnRpdGxlOiAnU2VsZiBSZWd1bGF0aW9uIE9udG9sb2d5IFJldGVzdCBEYXRhIFJlcG9ydCcKb3V0cHV0OgpnaXRodWJfZG9jdW1lbnQ6CnRvYzogeWVzCnRvY19mbG9hdDogeWVzCi0tLQoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CnNvdXJjZSgnL1VzZXJzL3pleW5lcGVua2F2aS9Ecm9wYm94L1BvbGRyYWNrTGFiL1NST19SZXRlc3RfQW5hbHlzZXMvY29kZS9TUk9fUmVwb3J0X0hlbHBlcl9GdW5jdGlvbnMuUicpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCiMgTWV0aG9kcwoKIyMgRGF0YSBjb2xsZWN0aW9uCgpUaGlzIHNhbXBsZSBjb25zaXN0cyBvZiBkYXRhIGZvciAxNTAgc3ViamVjdHMgb2YgdGhlIG9yaWdpbmFsIHNhbXBsZSBvZiA1MjIgdGhhdCBoYXMgY29tcGxldGVkIHRoZSBpbml0aWFsIGJhdHRlcnkgb2YgMzcgY29nbml0aXZlIHRhc2tzLCAyMyBzdXJ2ZXlzIGFuZCAzIHN1cnZleXMgb24gZGVtb2dyYXBoaWNzLiBEZXRhaWxzIG9mIHRoZSBvcmlnaW5hbCBzYW1wbGUgYXMgd2VsbCBhcyBxdWFsaXR5IGNvbnRyb2wgKHFjKSBwcm9jZWR1cmVzIGFyZSBkZXNjcmliZWQgZWxzZXdoZXJlIChFaXNlbmJlcmcgZXQgYWwuLCAyMDE3KS4gSW52aXRlZCBwYXJ0aWNpcGFudHMgd2VyZSBjaG9zZW4gcmFuZG9tbHkgYW5kIG9ubHkgc3Vic2V0cyBvZiB0aGVtIHdlcmUgaW52aXRlZCBmb3IgYSBnaXZlbiBiYXRjaCAoaW5zdGVhZCBvZiBvcGVuaW5nIHRoZSBiYXR0ZXJ5IHRvIGFsbCBxdWFsaWZpZWQgc3ViamVjdHMpIHdpdGggdGhlIGludGVudGlvbiB0byBhdm9pZCBhIHBvdGVudGlhbCBvdmVyc2FtcGxpbmcgYW5kIGJpYXMgdG93YXJkcyAiaGlnaCBzZWxmIHJlZ3VsYXRvcnMiLgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0Kd29ya2VycyA9IHJlYWQuY3N2KCcvVXNlcnMvemV5bmVwZW5rYXZpL0RvY3VtZW50cy9Qb2xkcmFja0xhYkxvY2FsL1NlbGZfUmVndWxhdGlvbl9PbnRvbG9neS9EYXRhL1JldGVzdF8wOS0yNy0yMDE3L0xvY2FsL1VzZXJfNzE3NTcwX3dvcmtlcnMuY3N2JykKd29ya2VycyA9IHdvcmtlcnMgJT4lIAogIGdyb3VwX2J5KFdvcmtlci5JRCkgJT4lCiAgbXV0YXRlKFJldGVzdF93b3JrZXI9aWZlbHNlKHN1bShDVVJSRU5ULlJldGVzdFdvcmtlcixDVVJSRU5ULlJldGVzdFdvcmtlckIyLENVUlJFTlQuUmV0ZXN0V29ya2VyQjMsQ1VSUkVOVC5SZXRlc3RXb3JrZXJCNCxDVVJSRU5ULlJldGVzdFdvcmtlckI1LG5hLnJtPVQpPjAsMSwwKSkgJT4lCiAgdW5ncm91cCgpCgp3b3JrZXJfY291bnRzIDwtIGZyb21KU09OKCcvVXNlcnMvemV5bmVwZW5rYXZpL0RvY3VtZW50cy9Qb2xkcmFja0xhYkxvY2FsL1NlbGZfUmVndWxhdGlvbl9PbnRvbG9neS9EYXRhL1JldGVzdF8wOS0yNy0yMDE3L0xvY2FsL3JldGVzdF93b3JrZXJfY291bnRzLmpzb24nKQoKd29ya2VyX2NvdW50cyA9IGFzLmRhdGEuZnJhbWUodW5saXN0KHdvcmtlcl9jb3VudHMpKQpuYW1lcyh3b3JrZXJfY291bnRzKSA9ICJ0YXNrX2NvdW50IgpgYGAKCkluIHRvdGFsIGByIHN1bSh3b3JrZXJzJFJldGVzdF93b3JrZXIpYCBwYXJ0aWNpcGFudHMgd2VyZSBpbnZpdGVkLCBgciBucm93KHdvcmtlcl9jb3VudHMpYCBiZWdhbiB0aGUgYmF0dGVyeSwgYHIgc3VtKHdvcmtlcl9jb3VudHMkdGFza19jb3VudCA+PSA2MilgIGNvbXBsZXRlZCB0aGUgYmF0dGVyeSBhbmQgMTUwIHByb3ZpZGVkIGRhdGEgdGhhdCBwYXNzZWQgcWMgZm9yIGJvdGggdGltZSBwb2ludHMuIE91ciB0YXJnZXQgc2FtcGxlIHNpemUgd2FzIGRldGVybWluZWQgaW4gYWR2YW5jZSBvZiBkYXRhIGNvbGxlY3Rpb24gYW5kIGRhdGEgY29sbGVjdGlvbiBjb250aW51ZWQgdW50aWwgdGhpcyBudW1iZXIgb2YgcGFydGljaXBhbnRzIHdpdGggZGF0YSB0aGF0IHN1cnZpdmVkIHFjIHdhcyByZWFjaGVkLgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KZGlzY19jb21wX2RhdGUgPSByZWFkLmNzdignL1VzZXJzL3pleW5lcGVua2F2aS9Eb2N1bWVudHMvUG9sZHJhY2tMYWJMb2NhbC9TZWxmX1JlZ3VsYXRpb25fT250b2xvZ3kvRGF0YS9SZXRlc3RfMDktMjctMjAxNy9Mb2NhbC9kaXNjb3ZlcnlfY29tcGxldGlvbl9kYXRlcy5jc3YnLCBoZWFkZXI9RkFMU0UpCnZhbF9jb21wX2RhdGUgPSByZWFkLmNzdignL1VzZXJzL3pleW5lcGVua2F2aS9Eb2N1bWVudHMvUG9sZHJhY2tMYWJMb2NhbC9TZWxmX1JlZ3VsYXRpb25fT250b2xvZ3kvRGF0YS9SZXRlc3RfMDktMjctMjAxNy9Mb2NhbC92YWxpZGF0aW9uX2NvbXBsZXRpb25fZGF0ZXMuY3N2JywgaGVhZGVyPUZBTFNFKQp0ZXN0X2NvbXBfZGF0ZSA9IHJiaW5kKGRpc2NfY29tcF9kYXRlLCB2YWxfY29tcF9kYXRlKQpybShkaXNjX2NvbXBfZGF0ZSwgdmFsX2NvbXBfZGF0ZSkKcmV0ZXN0X2NvbXBfZGF0ZSA9IHJlYWQuY3N2KCcvVXNlcnMvemV5bmVwZW5rYXZpL0RvY3VtZW50cy9Qb2xkcmFja0xhYkxvY2FsL1NlbGZfUmVndWxhdGlvbl9PbnRvbG9neS9EYXRhL1JldGVzdF8wOS0yNy0yMDE3L0xvY2FsL3JldGVzdF9jb21wbGV0aW9uX2RhdGVzLmNzdicsIGhlYWRlcj1GQUxTRSkKY29tcF9kYXRlcyA9IG1lcmdlKHJldGVzdF9jb21wX2RhdGUsIHRlc3RfY29tcF9kYXRlLCBieT0iVjEiKQpuYW1lcyhjb21wX2RhdGVzKSA8LSBjKCJzdWJfaWQiLCAicmV0ZXN0X2NvbXAiLCAidGVzdF9jb21wIikKY29tcF9kYXRlcyRyZXRlc3RfY29tcCA9IGFzLkRhdGUoY29tcF9kYXRlcyRyZXRlc3RfY29tcCkKY29tcF9kYXRlcyR0ZXN0X2NvbXAgPSBhcy5EYXRlKGNvbXBfZGF0ZXMkdGVzdF9jb21wKQpjb21wX2RhdGVzJGRheXNfYnR3ID0gd2l0aChjb21wX2RhdGVzLCByZXRlc3RfY29tcC10ZXN0X2NvbXApCmBgYAoKRGF0YSBjb2xsZWN0aW9uIHRvb2sgcGxhY2Ugb24gYXZlcmFnZSBgciByb3VuZChtZWFuKGFzLm51bWVyaWMoY29tcF9kYXRlcyRkYXlzX2J0dykpKWAgbnVtYmVyIG9mIGRheXMgYWZ0ZXIgdGhlIGNvbXBsZXRpb24gb2YgdGhlIGluaXRpYWwgYmF0dGVyeSB3aXRoIGEgcmFuZ2Ugb2YgYHIgcm91bmQocmFuZ2UoYXMubnVtZXJpYyhjb21wX2RhdGVzJGRheXNfYnR3KSkpWzFdYCB0byBgciByb3VuZChyYW5nZShhcy5udW1lcmljKGNvbXBfZGF0ZXMkZGF5c19idHcpKSlbMl1gIGRheXMuCgojIyBEZW1vZ3JhcGhpY3MKCmBgYHtyfQp0ZXN0X2RlbW9nIDwtIHJlYWQuY3N2KCcvVXNlcnMvemV5bmVwZW5rYXZpL0RvY3VtZW50cy9Qb2xkcmFja0xhYkxvY2FsL1NlbGZfUmVndWxhdGlvbl9PbnRvbG9neS9EYXRhL1JldGVzdF8wOS0yNy0yMDE3L3QxX2RhdGEvZGVtb2dyYXBoaWNfaGVhbHRoLmNzdicpCgpyZXRlc3RfZGVtb2cgPC0gcmVhZC5jc3YoJy9Vc2Vycy96ZXluZXBlbmthdmkvRG9jdW1lbnRzL1BvbGRyYWNrTGFiTG9jYWwvU2VsZl9SZWd1bGF0aW9uX09udG9sb2d5L0RhdGEvUmV0ZXN0XzA5LTI3LTIwMTcvZGVtb2dyYXBoaWNfaGVhbHRoLmNzdicpCgpyZXRlc3RfZGVtb2cgPSByZXRlc3RfZGVtb2dbcmV0ZXN0X2RlbW9nJFggJWluJSB0ZXN0X2RlbW9nJFgsXQoKbmFtZXModGVzdF9kZW1vZylbd2hpY2gobmFtZXModGVzdF9kZW1vZykgPT0gJ1gnKV0gPC0nc3ViX2lkJwpuYW1lcyhyZXRlc3RfZGVtb2cpW3doaWNoKG5hbWVzKHJldGVzdF9kZW1vZykgPT0gJ1gnKV0gPC0nc3ViX2lkJwoKc3VtbWFyeShyZXRlc3RfZGVtb2cgJT4lCiAgICAgICAgICBzZWxlY3QoU2V4LCBBZ2UpKQpgYGAKCiMjIExpdGVyYXR1cmUKCk9uZSB0aGUgbWFqb3IgY29udHJpYnV0aW9ucyBvZiB0aGlzIHByb2plY3QgaXMgYSBjb21wcmVoZW5zaXZlIGxpdGVyYXR1cmUgcmV2aWV3IG9mIHRoZSByZXRlc3QgcmVsaWFiaWxpdGllcyBvZiB0aGUgc3VydmV5cyBhbmQgdGFza3MgdGhhdCB3ZXJlIHVzZWQuIFdlIHJldmlld2VkIHRoZSBsaXRlcmF0dXJlIG9uIGEgbWVhc3VyZSAoYXMgb3Bwb3NlZCB0byB0YXNrIGxldmVsKSBwYXlpbmcgYXR0ZW50aW9uIHRvIGRpZmZlcmVuY2VzIGluIHNhbXBsZSBzaXplLCB0aGUgZGVsYXkgYmV0d2VlbiB0aGUgdHdvIG1lYXN1cmVtZW50cyBhcyB3ZWxsIGFzIHRoZSBzdGF0aXN0aWMgdGhhdCB3YXMgdXNlZCB0byBhc3Nlc3MgcmVsaWFiaWxpdGllcyAoZS5nLiBTcGVhcm1hbiB2cy4gUGVhcnNvbiBjb3JyZWxhdGlvbnMpLiBIZXJlIHdlIHByZXNlbnQgYSB0YWJsZSBhbmQgYSB2aXN1YWxpemF0aW9uIHN1bW1hcml6aW5nIG91ciBmaW5kaW5ncy4gUmVmZXJlbmNlcyBtZW50aW9uZWQgaW4gdGhlIHRhYmxlIGJlbG93IGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMWhjRUQ0X3JXU0dTRThUZDBhcVQwa1dxbExDQkF6Uk5LQlhqM3RTcmFtNTgvZWRpdD91c3A9c2hhcmluZykuICAKCmBgYHtyfQpsaXRfcmV2aWV3IDwtIHJlYWQuY3N2KCcvVXNlcnMvemV5bmVwZW5rYXZpL0Ryb3Bib3gvUG9sZHJhY2tMYWIvU1JPX1JldGVzdF9BbmFseXNlcy9pbnB1dC9saXRfcmV2aWV3X2ZpZ3VyZS5jc3YnKQoKbGl0X3JldmlldwpgYGAKCk1lYXN1cmUgbGV2ZWwgcGxvdAoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbGl0X3JldmlldyA9IGxpdF9yZXZpZXcgJT4lCiAgc2VwYXJhdGUoZHYsIGMoInRhc2tfZ3JvdXAiLCAidmFyIiksIHNlcD0iXFwuIixyZW1vdmU9RkFMU0UsZXh0cmE9Im1lcmdlIikgJT4lCiAgbXV0YXRlKHRhc2tfZ3JvdXAgPSBmYWN0b3IodGFza19ncm91cCwgbGV2ZWxzID0gdGFza19ncm91cFtvcmRlcih0YXNrKV0pLAogICAgICAgICB0eXBlID0gYXMuY2hhcmFjdGVyKHR5cGUpKSAlPiUKICBtdXRhdGUodGFza19ncm91cCA9IGdzdWIoIl8iLCAiICIsIHRhc2tfZ3JvdXApLAogICAgICAgICB2YXIgPSBnc3ViKCJfIiwgIiAiLCB2YXIpKSAlPiUKICBhcnJhbmdlKHRhc2tfZ3JvdXAsIHJhd19maXQsIHZhcikgJT4lCiAgbXV0YXRlKHRhc2tfZ3JvdXAgPSBpZmVsc2UodGFza19ncm91cCA9PSAicHN5Y2hvbG9naWNhbCByZWZyYWN0b3J5IHBlcmlvZCB0d28gY2hvaWNlcyIsICJwc3ljaG9sb2dpY2FsIHJlZnJhY3RvcnkgcGVyaW9kIiwgaWZlbHNlKHRhc2tfZ3JvdXAgPT0gImFuZ2xpbmcgcmlzayB0YXNrIGFsd2F5cyBzdW5ueSIsICJhbmdsaW5nIHJpc2sgdGFzayIsdGFza19ncm91cCkpKSAlPiUKICBtdXRhdGUodGFza19ncm91cCA9IGdzdWIoInN1cnZleSIsICIiLCB0YXNrX2dyb3VwKSkgJT4lCiAgICBzZWxlY3QoLW1lYXN1cmVfZGVzY3JpcHRpb24sIC1yZWZlcmVuY2UpCmBgYAoKYGBge3Igd2FybmluZz0gRkFMU0UsIG1lc3NhZ2UgPUZBTFNFLCBlY2hvPUZBTFNFfQpwMV9sZWdlbmQgPSBsaXRfcmV2aWV3ICU+JQogIGZpbHRlcih0YXNrID09ICd0YXNrJykgJT4lCmdncGxvdChhZXMoeSA9IHZhciwgeCA9IHJldGVzdF9yZWxpYWJpbGl0eSkpICsgCiAgZ2VvbV9wb2ludChhZXMoc2l6ZT1zYW1wbGVfc2l6ZSwgc2hhcGU9dHlwZSkpKwogIGZhY2V0X2dyaWQodGFza19ncm91cH4uLCBzd2l0Y2ggPSAieSIsIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlX3kiKSArCiAgdGhlbWUocGFuZWwuc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwgCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLAogICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZT0xODApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5ODAiKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJykgKyAKICB4bGFiKCIiKSsKICB5bGFiKCIiKSsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC4yNSwxKSwgYnJlYWtzPWMoLTAuMjUsIDAsIDAuMjUsIDAuNSwgMC43NSwgMSkpKwogIHNjYWxlX3NoYXBlX21hbnVhbChicmVha3MgPSBzb3J0KGxpdF9yZXZpZXckdHlwZSksIHZhbHVlcyA9IGMoMTUsIDE2LCAxNywgMykpCgpwMSA9IGxpdF9yZXZpZXcgJT4lCiAgZmlsdGVyKHRhc2sgPT0gJ3Rhc2snKSAlPiUKZ2dwbG90KGFlcyh5ID0gdmFyLCB4ID0gcmV0ZXN0X3JlbGlhYmlsaXR5KSkgKyAKICBnZW9tX3BvaW50KGFlcyhzaXplPXNhbXBsZV9zaXplLCBzaGFwZSA9IHR5cGUpLCBjb2xvcj0nIzAwQkZDNCcpKwogIGZhY2V0X2dyaWQodGFza19ncm91cH4uLCBzd2l0Y2ggPSAieSIsIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlX3kiKSArCiAgdGhlbWUocGFuZWwuc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwgCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLAogICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZT0xODApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5ODAiKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJykgKyAKICB4bGFiKCIiKSsKICB5bGFiKCIiKSsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC4yNSwxKSwgYnJlYWtzPWMoLTAuMjUsIDAsIDAuMjUsIDAuNSwgMC43NSwgMSkpKwogIHNjYWxlX3NoYXBlX21hbnVhbChicmVha3MgPSBzb3J0KGxpdF9yZXZpZXckdHlwZSksIHZhbHVlcyA9IGMoMTUsIDE2LCAxNywgMykpCgpwMiA9IGxpdF9yZXZpZXcgJT4lCiAgZmlsdGVyKHRhc2sgPT0gJ3N1cnZleScpICU+JQpnZ3Bsb3QoYWVzKHkgPSB2YXIsIHggPSByZXRlc3RfcmVsaWFiaWxpdHkpKSArIAogIGdlb21fcG9pbnQoYWVzKHNpemU9c2FtcGxlX3NpemUsIHNoYXBlID0gdHlwZSksIGNvbG9yID0gJyNGODc2NkQnKSsKICBmYWNldF9ncmlkKHRhc2tfZ3JvdXB+Liwgc3dpdGNoID0gInkiLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3BhY2UgPSAiZnJlZV95IikgKwogIHRoZW1lKHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGU9MTgwKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTgwIikpICsgCiAgeGxhYigiIikrCiAgeWxhYigiIikrCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTAuMjUsMSksIGJyZWFrcz1jKC0wLjI1LCAwLCAwLjI1LCAwLjUsIDAuNzUsIDEpKSsKICBzY2FsZV9zaGFwZV9tYW51YWwoYnJlYWtzID0gc29ydChsaXRfcmV2aWV3JHR5cGUpLCB2YWx1ZXMgPSBjKDE1LCAxNywgMykpCgpteWxlZ2VuZDwtZ19sZWdlbmQocDFfbGVnZW5kKQoKcDMgPC0gYXJyYW5nZUdyb2IoYXJyYW5nZUdyb2IocDEgK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgcDIgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3c9MSksCiAgICAgICAgICAgICBteWxlZ2VuZCwgbnJvdz0yLGhlaWdodHM9YygxMCwgMSkpCgpnZ3NhdmUoJ0xpdF9SZXZpZXdfUGxvdC5qcGcnLCBwbG90ID0gcDMsIGRldmljZSA9ICJqcGVnIiwgcGF0aCA9ICIvVXNlcnMvemV5bmVwZW5rYXZpL0Ryb3Bib3gvUG9sZHJhY2tMYWIvU1JPX1JldGVzdF9BbmFseXNlcy9vdXRwdXQvZmlndXJlcy8iLCB3aWR0aCA9IDI0LCBoZWlnaHQgPSAyMCwgdW5pdHMgPSAiaW4iLCBkcGk9MTAwKQpybShwMSwgcDIsIHAzLCBwMV9sZWdlbmQsIG15bGVnZW5kKQpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCcvVXNlcnMvemV5bmVwZW5rYXZpL0Ryb3Bib3gvUG9sZHJhY2tMYWIvU1JPX1JldGVzdF9BbmFseXNlcy9vdXRwdXQvZmlndXJlcy9MaXRfUmV2aWV3X1Bsb3QuanBnJykKYGBgCgpCZWNhdXNlIHRoaXMgcGxvdCBpcyBkaWZmaWN1bHQgdG8gZGlnZXN0IHdlIHN1bW1hcml6ZSBpdCBvbiBhIHRhc2sgbGV2ZWwgdG8gZ2l2ZSBhIGdlbmVyYWwgc2Vuc2Ugb2YgdGhlIG1haW4gdGFrZWF3YXlzLiBUaGlzIHBsb3QgbmF0dXJhbGx5IGRpc3JlZ2FyZHMgbXVjaCBvZiB0aGUgZmluZSBncmFpbmVkIGluZm9ybWF0aW9uLgoKYGBge3J9CnAxX3RfbGVnZW5kIDwtIGxpdF9yZXZpZXcgJT4lCiAgZmlsdGVyKHRhc2sgPT0gJ3Rhc2snKSAlPiUKZ2dwbG90KGFlcyh5ID0gZmFjdG9yKHRhc2tfZ3JvdXAsIGxldmVscz1yZXYodW5pcXVlKHRhc2tfZ3JvdXApKSksIHggPSByZXRlc3RfcmVsaWFiaWxpdHkpKSArIAogIGdlb21fcG9pbnQoYWVzKHNpemU9c2FtcGxlX3NpemUsIHNoYXBlID0gdHlwZSksIGNvbG9yPSdibGFjaycpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT00MyksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0yMyksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MzApLCAKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgCiAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMC43NSwgImluY2hlcyIpLCAKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yOCksCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueCA9IHVuaXQoMC41LCAiaW5jaGVzIikpICsgCiAgZ3VpZGVzKHNpemUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPWMoOSwxOCwyOCkpKSwKICAgICAgICAgc2hhcGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTE4KSkpKwogIHhsYWIoIlJlbGlhYmlsaXR5IikrCiAgeWxhYigiIikrCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTAuMjUsMSksIGJyZWFrcz1jKC0wLjI1LCAwLCAwLjI1LCAwLjUsIDAuNzUsIDEpKSsKICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHN0cl93cmFwKHgsIHdpZHRoID0gMTApKSsKICBzY2FsZV9zaGFwZV9tYW51YWwoYnJlYWtzID0gc29ydChsaXRfcmV2aWV3JHR5cGUpLCB2YWx1ZXMgPSBjKDE1LCAxNiwgMTcsIDMpLCBuYW1lPSJUeXBlIikrCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKG5hbWUgPSAiU2FtcGxlIFNpemUiKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMSkKCnAxX3QgPC0gbGl0X3JldmlldyAlPiUKICBmaWx0ZXIodGFzayA9PSAndGFzaycpICU+JQpnZ3Bsb3QoYWVzKHkgPSBmYWN0b3IodGFza19ncm91cCwgbGV2ZWxzPXJldih1bmlxdWUodGFza19ncm91cCkpKSwgeCA9IHJldGVzdF9yZWxpYWJpbGl0eSkpICsgCiAgZ2VvbV9wb2ludChhZXMoc2l6ZT1zYW1wbGVfc2l6ZSwgc2hhcGUgPSB0eXBlKSwgY29sb3I9JyMwMEJGQzQnKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9NDMpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJywKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTIzKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZT0zMCkpICsgCiAgeGxhYigiUmVsaWFiaWxpdHkiKSsKICB5bGFiKCIiKSsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC4yNSwxKSwgYnJlYWtzPWMoLTAuMjUsIDAsIDAuMjUsIDAuNSwgMC43NSwgMSkpKwogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gZnVuY3Rpb24oeCkgc3RyX3dyYXAoeCwgd2lkdGggPSAxMCkpKwogIHNjYWxlX3NoYXBlX21hbnVhbChicmVha3MgPSBzb3J0KGxpdF9yZXZpZXckdHlwZSksIHZhbHVlcyA9IGMoMTUsIDE2LCAxNywgMykpKwogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoNSwgMzUpKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMSkKCnAyX3QgPC0gbGl0X3JldmlldyAlPiUKICBmaWx0ZXIodGFzayA9PSAnc3VydmV5JykgJT4lCmdncGxvdChhZXMoeSA9IGZhY3Rvcih0YXNrX2dyb3VwLCBsZXZlbHM9cmV2KHVuaXF1ZSh0YXNrX2dyb3VwKSkpLCB4ID0gcmV0ZXN0X3JlbGlhYmlsaXR5KSkgKyAKICBnZW9tX3BvaW50KGFlcyhzaXplPXNhbXBsZV9zaXplLCBzaGFwZSA9IHR5cGUpLCBjb2xvcj0nI0Y4NzY2RCcpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT00MyksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MjMpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPTMwKSkgKyAKICB4bGFiKCJSZWxpYWJpbGl0eSIpKwogIHlsYWIoIiIpKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC0wLjI1LDEpLCBicmVha3M9YygtMC4yNSwgMCwgMC4yNSwgMC41LCAwLjc1LCAxKSkrCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJfd3JhcCh4LCB3aWR0aCA9IDEwKSkrCiAgc2NhbGVfc2hhcGVfbWFudWFsKGJyZWFrcyA9IHNvcnQobGl0X3JldmlldyR0eXBlKSwgdmFsdWVzID0gYygxNSwgMTYsIDE3LCAzKSkrCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYyg1LCAzNSkpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZCIsIHNpemUgPSAxKQoKbXlsZWdlbmQ8LWdfbGVnZW5kKHAxX3RfbGVnZW5kKQoKcDNfdCA8LSBhcnJhbmdlR3JvYihhcnJhbmdlR3JvYihwMV90LCBwMl90LCBucm93PTEpLCBteWxlZ2VuZCwgbnJvdz0yLGhlaWdodHM9YygxMCwgMSkpCgpnZ3NhdmUoJ0xpdF9SZXZpZXdfUGxvdF90LmpwZycsIHBsb3QgPSBwM190LCBkZXZpY2UgPSAianBlZyIsIHBhdGggPSAiL1VzZXJzL3pleW5lcGVua2F2aS9Ecm9wYm94L1BvbGRyYWNrTGFiL1NST19SZXRlc3RfQW5hbHlzZXMvb3V0cHV0L2ZpZ3VyZXMvIiwgd2lkdGggPSAyNywgaGVpZ2h0ID0gNDgsIHVuaXRzID0gImluIiwgbGltaXRzaXplID0gRkFMU0UsIGRwaSA9IDcyKQpybShwMV90LCBwMl90LCBwM190LCBteWxlZ2VuZCwgcDFfdF9sZWdlbmQpCmBgYAoKYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPScxMDAlJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJy9Vc2Vycy96ZXluZXBlbmthdmkvRHJvcGJveC9Qb2xkcmFja0xhYi9TUk9fUmV0ZXN0X0FuYWx5c2VzL291dHB1dC9maWd1cmVzL0xpdF9SZXZpZXdfUGxvdF90LmpwZycpCmBgYAoKQW4gaW50ZXJhY3RpdmUgdmVyc2lvbiBvZiB0aGlzIHBsb3QgY291bGQgYmUgZmluZCBbaGVyZV0oaHR0cHM6Ly96ZW5rYXZpLmdpdGh1Yi5pby9TUk9fUmV0ZXN0X0FuYWx5c2VzL291dHB1dC9yZXBvcnRzL0xpdF9SZXZpZXdfRmlndXJlLmh0bWwpCgpUYWtlYXdheXMgZnJvbSB0aGlzIHJldmlldyBhcmU6IAotIFN1cnZleSBtZWFzdXJlcyBoYXZlIGJlZW4gcmVwb3J0ZWQgdG8gaGlnaGVyIHJlbGlhYmlsaXR5IGNvbXBhcmVkIHRvIHRhc2sgbWVhc3VyZXMgIAotIFN1cnZleSBtZWFzdXJlcyBoYXZlIGxlc3MgdmFyaWFiaWxpdHkgaW4gdGhlIHJlcG9ydGVkIHJlbGlhYmlsdGl5IGVzdGltYXRlcyBjb21wYXJlZCB0byB0YXNrIG1lYXN1cmVzJyAKCiMjIExvYWRpbmcgZGF0YXNldHMKClRoZSB2YXJpYWJsZXMgaW5jbHVkZWQgaW4gdGhpcyByZXBvcnQgYXJlOiAgCi0gbWVhbmluZ2Z1bCB2YXJpYWJsZXMgKGluY2x1ZGVzIG9ubHkgaGRkZG0gcGFyYW1ldGVycykgIAotIEVaIGRpZmZ1c2lvbiBwYXJhbWV0ZXJzICAKLSBSYXcgUlQgYW5kIEFjY3VyYWN5IG1lYXN1cmVzICAKLSBWYXJpYWJsZXMgZm91bmQgaW4gdGhlIGxpdGVyYXR1cmUgKGZvciBjb21wYXJpc29uKSAgCgpgYGB7ciBlY2hvPUZBTFNFfQojR2V0IHZhcmlhYmxlcyBvZiBpbnRlcmVzdCBmcm9tIElhbidzIHJlbGVhc2UKdG1wMSA8LSByZWFkLmNzdignL1VzZXJzL3pleW5lcGVua2F2aS9Eb2N1bWVudHMvUG9sZHJhY2tMYWJMb2NhbC9TZWxmX1JlZ3VsYXRpb25fT250b2xvZ3kvRGF0YS9Db21wbGV0ZV8xMC0wOC0yMDE3L21lYW5pbmdmdWxfdmFyaWFibGVzLmNzdicpCnRtcDIgPC0gcmVhZC5jc3YoJy9Vc2Vycy96ZXluZXBlbmthdmkvRG9jdW1lbnRzL1BvbGRyYWNrTGFiTG9jYWwvU2VsZl9SZWd1bGF0aW9uX09udG9sb2d5L0RhdGEvQ29tcGxldGVfMTAtMDgtMjAxNy9tZWFuaW5nZnVsX3ZhcmlhYmxlc19ub0RETS5jc3YnKQp0bXAzIDwtIHJlYWQuY3N2KCcvVXNlcnMvemV5bmVwZW5rYXZpL0RvY3VtZW50cy9Qb2xkcmFja0xhYkxvY2FsL1NlbGZfUmVndWxhdGlvbl9PbnRvbG9neS9EYXRhL0NvbXBsZXRlXzEwLTA4LTIwMTcvbWVhbmluZ2Z1bF92YXJpYWJsZXNfRVouY3N2JykKcmV0ZXN0X3JlcG9ydF92YXJzID0gYyhuYW1lcyh0bXAxKSwgbmFtZXModG1wMiksIG5hbWVzKHRtcDMpKQpyZXRlc3RfcmVwb3J0X3ZhcnMgPSB1bmlxdWUocmV0ZXN0X3JlcG9ydF92YXJzKQpsaXRfcmV2X3ZhcnMgPSBhcy5jaGFyYWN0ZXIodW5pcXVlKGxpdF9yZXZpZXckZHYpW3doaWNoKHVuaXF1ZShsaXRfcmV2aWV3JGR2KSAlaW4lIHJldGVzdF9yZXBvcnRfdmFycyA9PSBGQUxTRSldKQpyZXRlc3RfcmVwb3J0X3ZhcnMgPSBjKHJldGVzdF9yZXBvcnRfdmFycywgbGl0X3Jldl92YXJzKQpybSh0bXAxLCB0bXAyLCB0bXAzLCBsaXRfcmV2X3ZhcnMpCmBgYAoKIyMjIExvYWQgdGltZSAxIGRhdGEKYGBge3J9CnRlc3RfZGF0YSA8LSByZWFkLmNzdignL1VzZXJzL3pleW5lcGVua2F2aS9Eb2N1bWVudHMvUG9sZHJhY2tMYWJMb2NhbC9TZWxmX1JlZ3VsYXRpb25fT250b2xvZ3kvRGF0YS9SZXRlc3RfMDktMjctMjAxNy90MV9kYXRhL3ZhcmlhYmxlc19leGhhdXN0aXZlLmNzdicpCgp0ZXN0X2RhdGEgPC0gdGVzdF9kYXRhWyxuYW1lcyh0ZXN0X2RhdGEpICVpbiUgcmV0ZXN0X3JlcG9ydF92YXJzXQoKdGVzdF9kYXRhJFggPC0gYXMuY2hhcmFjdGVyKHRlc3RfZGF0YSRYKQpuYW1lcyh0ZXN0X2RhdGEpW3doaWNoKG5hbWVzKHRlc3RfZGF0YSkgPT0gJ1gnKV0gPC0nc3ViX2lkJyAKYGBgCgpGb3IgcmVmZXJlbmNlIGhlcmUgYXJlIHRoZSB2YXJpYWJsZXMgdGhhdCBhcmUgKipub3QqKiBpbmNsdWRlZCBpbiB0aGUgYW5hbHlzZXMgb2YgdGhlIHJlbWFpbmRlciBvZiB0aGlzIHJlcG9ydCBiZWNhdXNlIHRoZXkgd2VyZSBub3Qgb2YgdGhlb3JldGljYWwgaW50ZXJlc3QgaW4gZmFjdG9yIHN0cnVjdHVyZSBhbmFseXNlcyBvZiB0aGlzIGRhdGEgc28gZmFyLiBUaGVzZSBpbmNsdWRlIGRyaWZ0IGRpZmZ1c2lvbiBhbmQgb3RoZXIgbW9kZWwgcGFyYW1ldGVycyBmb3Igc3BlY2lmaWMgY29uZGl0aW9ucyB3aXRoaW4gYSB0YXNrOyBzdXJ2ZXkgdmFyaWFibGVzIHRoYXQgYXJlIG5vdCBwYXJ0IG9mIHRoZSBkZXBlbmRhbnQgdmFyaWFibGVzIGZvciB0aGF0IHN1cnZleSBpbiB0aGUgbGl0ZXJhdHVyZSBhbmQgZGVtb2dyYXBoaWNzICh0aGVzZSBhcmUgc2F2ZWQgZm9yIHByZWRpY3Rpb24gYW5hbHlzZXMpLgoKYGBge3J9CnRlc3RfZGF0YTIgPC0gcmVhZC5jc3YoJy9Vc2Vycy96ZXluZXBlbmthdmkvRG9jdW1lbnRzL1BvbGRyYWNrTGFiTG9jYWwvU2VsZl9SZWd1bGF0aW9uX09udG9sb2d5L0RhdGEvUmV0ZXN0XzA5LTI3LTIwMTcvdDFfZGF0YS92YXJpYWJsZXNfZXhoYXVzdGl2ZS5jc3YnKQoKZGYgPC0gZGF0YS5mcmFtZShuYW1lcyh0ZXN0X2RhdGEyKVt3aGljaChuYW1lcyh0ZXN0X2RhdGEyKSAlaW4lIG5hbWVzKHRlc3RfZGF0YSkgPT0gRkFMU0UpXSkKbmFtZXMoZGYpID0gYygndmFycycpCgpkZgpgYGAKCmBgYHtyIGVjaG89RkFMU0V9CnJtKHRlc3RfZGF0YTIsIGRmKQpgYGAKCiMjIyBMb2FkIHRpbWUgMiBkYXRhIApgYGB7cn0KcmV0ZXN0X2RhdGEgPC0gcmVhZC5jc3YoJy9Vc2Vycy96ZXluZXBlbmthdmkvRG9jdW1lbnRzL1BvbGRyYWNrTGFiTG9jYWwvU2VsZl9SZWd1bGF0aW9uX09udG9sb2d5L0RhdGEvUmV0ZXN0XzA5LTI3LTIwMTcvdmFyaWFibGVzX2V4aGF1c3RpdmUuY3N2JykKCnJldGVzdF9kYXRhIDwtIHJldGVzdF9kYXRhWyxuYW1lcyhyZXRlc3RfZGF0YSkgJWluJSByZXRlc3RfcmVwb3J0X3ZhcnNdCgpyZXRlc3RfZGF0YSRYIDwtIGFzLmNoYXJhY3RlcihyZXRlc3RfZGF0YSRYKQpuYW1lcyhyZXRlc3RfZGF0YSlbd2hpY2gobmFtZXMocmV0ZXN0X2RhdGEpID09ICdYJyldIDwtJ3N1Yl9pZCcgCnJldGVzdF9kYXRhID0gcmV0ZXN0X2RhdGFbcmV0ZXN0X2RhdGEkc3ViX2lkICVpbiUgdGVzdF9kYXRhJHN1Yl9pZCxdCmBgYAoKIyMjIFJlcGxhY2UgSERETSBwYXJhbWV0ZXJzIGluIHQxIGRhdGEKClNpbmNlIEhERE0gcGFyYW1ldGVycyBkZXBlbmQgb24gdGhlIHNhbXBsZSBvbiB3aGljaCB0aGV5IGFyZSBmaXQgd2UgcmVmaXQgdGhlIG1vZGVsIG9uIHQxIGRhdGEgZm9yIHRoZSBzdWJqZWN0cyB0aGF0IGhhdmUgdDIgZGF0YS4gSGVyZSB3ZSByZXBsYWNlIHRoZSBIRERNIHBhcmFtZXRlcnMgaW4gdGhlIGN1cnJlbnQgdDEgZGF0YXNldCB3aXRoIHRoZXNlIHJlZml0dGVkIHZhbHVlcy4gCgpgYGB7cn0KaGRkbV9yZWZpdHMgPC0gcmVhZC5jc3YoJy9Vc2Vycy96ZXluZXBlbmthdmkvRG9jdW1lbnRzL1BvbGRyYWNrTGFiTG9jYWwvU2VsZl9SZWd1bGF0aW9uX09udG9sb2d5L0RhdGEvUmV0ZXN0XzAzLTIxLTIwMTcvaGRkbV9yZWZpdHNfZXhoYXVzdGl2ZS5jc3YnKQoKaGRkbV9yZWZpdHMgPSBoZGRtX3JlZml0c1ssbmFtZXMoaGRkbV9yZWZpdHMpICVpbiUgcmV0ZXN0X3JlcG9ydF92YXJzXQoKaGRkbV9yZWZpdHMkWCA8LSBhcy5jaGFyYWN0ZXIoaGRkbV9yZWZpdHMkWCkKbmFtZXMoaGRkbV9yZWZpdHMpW3doaWNoKG5hbWVzKGhkZG1fcmVmaXRzKSA9PSAnWCcpXSA8LSdzdWJfaWQnIAoKI0ZvciBsYXRlciBjb21wYXJpc29uIG9mIHdoZXRoZXIgZml0dGluZyB0aGUgRERNIHBhcmFtZXRlcnMgb24gZnVsbCBvciByZXRlc3Qgc2FtcGxlIG1ha2VzIGEgYmlnIGRpZmZlcmVuY2UKdGVzdF9kYXRhX2Z1bGxfc2FtcGxlX2hkZG0gPC0gdGVzdF9kYXRhCgp0ZXN0X2RhdGEgPSBjYmluZCh0ZXN0X2RhdGEkc3ViX2lkLCB0ZXN0X2RhdGFbLG5hbWVzKHRlc3RfZGF0YSkgJWluJSBuYW1lcyhoZGRtX3JlZml0cykgPT0gRkFMU0VdKQoKbmFtZXModGVzdF9kYXRhKVt3aGljaChuYW1lcyh0ZXN0X2RhdGEpID09ICd0ZXN0X2RhdGEkc3ViX2lkJyldIDwtJ3N1Yl9pZCcKCnRlc3RfZGF0YSA9IG1lcmdlKHRlc3RfZGF0YSwgaGRkbV9yZWZpdHMsIGJ5PSJzdWJfaWQiKQpgYGAKCiMgUmVzdWx0cwoKIyMgRGVtb2dyYXBoaWNzIHJlbGlhYmlsaXR5CgpQb2ludCBlc3RpbWF0ZXMgb2YgcmVsaWFiaWxpdHkgZm9yIHRoZSBkZW1vZ3JhcGhpYyB2YXJpYWJlbHMuCgpgYGB7cn0KbnVtZXJpY19jb2xzID0gYygpCgpmb3IoaSBpbiAxOmxlbmd0aChuYW1lcyh0ZXN0X2RlbW9nKSkpewogIGlmKGlzLm51bWVyaWModGVzdF9kZW1vZ1ssaV0pKXsKICAgIG51bWVyaWNfY29scyA8LSBjKG51bWVyaWNfY29scywgbmFtZXModGVzdF9kZW1vZylbaV0pCiAgfQp9CgpkZW1vZ19yZWxfZGYgPC0gZGF0YS5mcmFtZShzcGVhcm1hbiA9IHJlcChOQSwgbGVuZ3RoKG51bWVyaWNfY29scykpLAogICAgICAgICAgICAgICAgICAgICBpY2MgPSByZXAoTkEsIGxlbmd0aChudW1lcmljX2NvbHMpKSwKICAgICAgICAgICAgICAgICAgICAgcGVhcnNvbiA9IHJlcChOQSwgbGVuZ3RoKG51bWVyaWNfY29scykpKQoKcm93Lm5hbWVzKGRlbW9nX3JlbF9kZikgPC0gbnVtZXJpY19jb2xzCgpmb3IoaSBpbiAxOmxlbmd0aChudW1lcmljX2NvbHMpKXsKICBkZW1vZ19yZWxfZGZbbnVtZXJpY19jb2xzW2ldLCAnc3BlYXJtYW4nXSA8LSBnZXRfc3BlYXJtYW4obnVtZXJpY19jb2xzW2ldLCB0MV9kZiA9IHRlc3RfZGVtb2csIHQyX2RmID0gcmV0ZXN0X2RlbW9nKSAKICBkZW1vZ19yZWxfZGZbbnVtZXJpY19jb2xzW2ldLCAnaWNjJ10gPC0gZ2V0X2ljYyhudW1lcmljX2NvbHNbaV0sIHQxX2RmID0gdGVzdF9kZW1vZywgdDJfZGYgPSByZXRlc3RfZGVtb2cpCiAgZGVtb2dfcmVsX2RmW251bWVyaWNfY29sc1tpXSwgJ3BlYXJzb24nXSA8LSBnZXRfcGVhcnNvbihudW1lcmljX2NvbHNbaV0sIHQxX2RmID0gdGVzdF9kZW1vZywgdDJfZGYgPSByZXRlc3RfZGVtb2cpCn0KCmRlbW9nX3JlbF9kZiAlPiUKICBtdXRhdGUodmFyID0gcm93Lm5hbWVzKC4pKSAlPiUKICBzZWxlY3QodmFyLCBpY2MsIHNwZWFybWFuLCBwZWFyc29uKSAlPiUKICBhcnJhbmdlKC1pY2MpCmBgYAoKYGBge3IgZWNobz1GQUxTRX0Kcm0odGVzdF9kZW1vZywgcmV0ZXN0X2RlbW9nLCBkZW1vZ19yZWxfZGYsIG51bWVyaWNfY29scykKYGBgCgojIyBSZWxhdGlvbnNoaXAgYmV0d2VlbiByZWxpYWJpbGl0eSBtZXRyaWNzIChwb2ludCBlc3RpbWF0ZXMpCgpCYXNlZCBvbiBbV2VpciAoMjAwNSldKGh0dHBzOi8vcGRmcy5zZW1hbnRpY3NjaG9sYXIub3JnL2Q5OWEvNzkwY2NlNDNmN2YyMGQ3NDJmOWQzNzliNzlkZTRmNzY3NzQwLnBkZikgSUNDKDMsaykgZG9lcyBub3QgdGFrZSBpbiB0byBhY2NvdW50IHdpdGhpbiBzdWJqZWN0IGRpZmZlcmVuY2VzIGJldHdlZW4gdHdvIHRpbWUgcG9pbnRzIChpLmUuIHRoZSBmaXhlZCBlZmZlY3Qgb2YgdGltZS9zeXN0ZW1hdGljIGVycm9yKS4gVGh1cywgaXQgaXMgd2VsbCBhcHByb3hpbWF0ZWQgYnkgUGVhcnNvbidzIHIgYW5kIHN1YmplY3QgdG8gc2ltaWxhciBjcml0aWNpc21zLiBbV2VpciAoMjAwNSldKGh0dHBzOi8vcGRmcy5zZW1hbnRpY3NjaG9sYXIub3JnL2Q5OWEvNzkwY2NlNDNmN2YyMGQ3NDJmOWQzNzliNzlkZTRmNzY3NzQwLnBkZikgc3VnZ2VzdHMgcmVwb3J0aW5nIGF0IGxlYXN0IHRoaXMgc3lzdGVtYXRpYyBlcnJvciBlZmZlY3Qgc2l6ZSBpZiBvbmUgY2hvb3NlcyB0byByZXBvcnQgd2l0aCBJQ0MoMyxrKS4gQmFzZWQgb24gaGlzIGNvbmNsdXNpb25zIGhlcmUgSSByZXBvcnQ6ICAKLSBJQ0MoMyxrKTogQXMgRGF2ZSBjbGFyaWZpZWQgdGhpcyByYW5nZXMgZnJvbSAxIHRvIC0xLyhudW1iZXIgb2YgcmVwZWF0ZWQgbWVhc3VyZXMgLTEpIHNvIGluIG91ciBjYXNlIHRoaXMgcmFuZ2Ugd291bGQgYmUgWy0xLCAxXTsgbGFyZ2VyIHZhbHVlcyB3b3VsZCBtZWFuIHRoYXQgdGhlIHR3byBzY29yZXMgb2YgYSBzdWJqZWN0IGZvciBhIGdpdmVuIG1lYXN1cmUgYXJlIG1vcmUgc2ltaWxhciB0byBlYWNoIG90aGVyIHRoYW4gdGhleSBhcmUgdG8gc2NvcmVzIG9mIG90aGVyIHBlb3BsZSAgCi0gcGFydGlhbCAkXGV0YV4yJCBmb3IgdGltZSAoJFNTX3t0aW1lfS9TU197d2l0aGlufSQpOiBlZmZlY3Qgc2l6ZSBvZiB0aW1lICAgCi0gU0VNICgkXHNxcnQoTVNfe2Vycm9yfSkkKTogc3RhbmRhcmQgZXJyb3Igb2YgbWVhc3VyZW1lbnQ7IHRoZSBzbWFsbGVyIHRoZSBiZXR0ZXIKCmBgYHtyfQojQ3JlYXRlIGRmIG9mIHBvaW50IGVzdGltYXRlIHJlbGlhYmlsaXRpZXMKbnVtZXJpY19jb2xzID0gYygpCgpmb3IoaSBpbiAxOmxlbmd0aChuYW1lcyh0ZXN0X2RhdGEpKSl7CiAgaWYoaXMubnVtZXJpYyh0ZXN0X2RhdGFbLGldKSAmIG5hbWVzKHRlc3RfZGF0YSlbaV0gJWluJSBuYW1lcyhyZXRlc3RfZGF0YSkpewogICAgbnVtZXJpY19jb2xzIDwtIGMobnVtZXJpY19jb2xzLCBuYW1lcyh0ZXN0X2RhdGEpW2ldKQogIH0KfQoKcmVsX2RmIDwtIGRhdGEuZnJhbWUoc3BlYXJtYW4gPSByZXAoTkEsIGxlbmd0aChudW1lcmljX2NvbHMpKSwKICAgICAgICAgICAgICAgICAgICAgaWNjID0gcmVwKE5BLCBsZW5ndGgobnVtZXJpY19jb2xzKSksCiAgICAgICAgICAgICAgICAgICAgIHBlYXJzb24gPSByZXAoTkEsIGxlbmd0aChudW1lcmljX2NvbHMpKSwKICAgICAgICAgICAgICAgICAgICAgZXRhX3NxID0gcmVwKE5BLCBsZW5ndGgobnVtZXJpY19jb2xzKSksCiAgICAgICAgICAgICAgICAgICAgIHNlbSA9IHJlcChOQSwgbGVuZ3RoKG51bWVyaWNfY29scykpLAogICAgICAgICAgICAgICAgICAgICB2YXJfc3VicyA9IHJlcChOQSwgbGVuZ3RoKG51bWVyaWNfY29scykpLAogICAgICAgICAgICAgICAgICAgICB2YXJfaW5kID0gcmVwKE5BLCBsZW5ndGgobnVtZXJpY19jb2xzKSksCiAgICAgICAgICAgICAgICAgICAgIHZhcl9yZXNpZCA9IHJlcChOQSwgbGVuZ3RoKG51bWVyaWNfY29scykpKQoKcm93Lm5hbWVzKHJlbF9kZikgPC0gbnVtZXJpY19jb2xzCgpmb3IoaSBpbiAxOmxlbmd0aChudW1lcmljX2NvbHMpKXsKICByZWxfZGZbbnVtZXJpY19jb2xzW2ldLCAnc3BlYXJtYW4nXSA8LSBnZXRfc3BlYXJtYW4obnVtZXJpY19jb2xzW2ldKSAKICByZWxfZGZbbnVtZXJpY19jb2xzW2ldLCAnaWNjJ10gPC0gZ2V0X2ljYyhudW1lcmljX2NvbHNbaV0pCiAgcmVsX2RmW251bWVyaWNfY29sc1tpXSwgJ3BlYXJzb24nXSA8LSBnZXRfcGVhcnNvbihudW1lcmljX2NvbHNbaV0pCiAgcmVsX2RmW251bWVyaWNfY29sc1tpXSwgJ2V0YV9zcSddIDwtIGdldF9ldGEobnVtZXJpY19jb2xzW2ldKQogIHJlbF9kZltudW1lcmljX2NvbHNbaV0sICdzZW0nXSA8LSBnZXRfc2VtKG51bWVyaWNfY29sc1tpXSkKICByZWxfZGZbbnVtZXJpY19jb2xzW2ldLCAndmFyX3N1YnMnXSA8LSBnZXRfdmFyX2JyZWFrZG93bihudW1lcmljX2NvbHNbaV0pJHN1YnMKICByZWxfZGZbbnVtZXJpY19jb2xzW2ldLCAndmFyX2luZCddIDwtIGdldF92YXJfYnJlYWtkb3duKG51bWVyaWNfY29sc1tpXSkkaW5kCiAgcmVsX2RmW251bWVyaWNfY29sc1tpXSwgJ3Zhcl9yZXNpZCddIDwtIGdldF92YXJfYnJlYWtkb3duKG51bWVyaWNfY29sc1tpXSkkcmVzaWQKfQoKcmVsX2RmJGR2ID0gcm93Lm5hbWVzKHJlbF9kZikKcm93Lm5hbWVzKHJlbF9kZikgPSBzZXEoMTpucm93KHJlbF9kZikpCnJlbF9kZiR0YXNrID0gJ3Rhc2snCnJlbF9kZltncmVwKCdzdXJ2ZXknLCByZWxfZGYkZHYpLCAndGFzayddID0gJ3N1cnZleScKcmVsX2RmW2dyZXAoJ2hvbHQnLCByZWxfZGYkZHYpLCAndGFzayddID0gInRhc2siCnJlbF9kZiA9IHJlbF9kZiAlPiUKICBzZWxlY3QoZHYsIHRhc2ssIHNwZWFybWFuLCBpY2MsIHBlYXJzb24sIGV0YV9zcSwgc2VtLCB2YXJfc3VicywgdmFyX2luZCwgdmFyX3Jlc2lkKQojIHJvdy5uYW1lcyhyZWxfZGYpID0gTlVMTApgYGAKClRob3VnaCB3ZSBhcmUgcHJpbWFyaWx5IHJlcG9ydGluZyBJQ0MncyBhcyBvdXIgbWV0cmljIG9mIHJlbGlhYmlsaXR5IHRoZSByZXN1bHRzIGRvbid0IGNoYW5nZSBkZXBlbmRpbmcgb24gdGhlIG1ldHJpYyBjaG9zZW4uIEhlcmUgd2UgcGxvdCBwb2ludCBlc3RpbWF0ZXMgb2YgdGhyZWUgZGlmZmVyZW50IHJlbGlhYmlsaXR5IG1ldHJpY3MgYWdhaW5zdCBlYWNoIG90aGVyIChJQ0MsIFBlYXJzb24sIFNwZWFybWFuKS4gVGhlIGJvb3RzdHJhcHBlZCB2ZXJzaW9uIGlzIGVzc2VudGlhbGx5IHRoZSBzYW1lIGJ1dCB0aGUgcGxvdHMgYXJlIGJ1c2llciBkdWUgdG8gbW9yZSBkYXRhcG9pbnRzLgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KcDEgPSByZWxfZGYgJT4lCiAgZ2dwbG90KGFlcyhzcGVhcm1hbiwgaWNjLCBjb2w9dGFzaykpKwogIGdlb21fcG9pbnQoKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKwogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlPTEpCgpwMiA9IHJlbF9kZiAlPiUKICBnZ3Bsb3QoYWVzKHBlYXJzb24sIGljYywgY29sPXRhc2spKSsKICBnZW9tX3BvaW50KCkrCiAgdGhlbWVfYncoKSsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsKICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZT0xKQoKcDMgPSByZWxfZGYgJT4lCiAgZ2dwbG90KGFlcyhwZWFyc29uLCBzcGVhcm1hbiwgY29sPXRhc2spKSsKICBnZW9tX3BvaW50KCkrCiAgdGhlbWVfYncoKSsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsKICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZT0xKQoKZ3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIG5yb3c9MSkKCmdnc2F2ZSgnTWV0cmljX1NjYXR0ZXJwbG90cy5qcGcnLCBwbG90ID0gZ3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIG5yb3c9MSksIGRldmljZSA9ICJqcGVnIiwgcGF0aCA9ICIvVXNlcnMvemV5bmVwZW5rYXZpL0Ryb3Bib3gvUG9sZHJhY2tMYWIvU1JPX1JldGVzdF9BbmFseXNlcy9vdXRwdXQvZmlndXJlcy8iLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA0LCB1bml0cyA9ICJpbiIsIGxpbWl0c2l6ZSA9IEZBTFNFKQpgYGAKCmBgYHtyIGVjaG89RkFMU0V9CnJtKHAxLHAyLHAzKQpgYGAKCk5vdGU6IFNvbWUgdmFyaWFibGVzIGhhdmUgPDAgSUNDJ3MuIFRoaXMgd291bGQgYmUgdGhlIGNhc2UgaWYgdGhlICRNU197ZXJyb3J9JD4kTVNfe2JldHdlZW59JC4gRGF0YSBmb3IgdGhlc2UgdmFyaWFibGVzIGhhdmUgbm8gcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHR3byB0aW1lIHBvaW50cy4KCiMjIFN1bW1hcnkgb2YgYWxsIG1lYXN1cmUgcmVsaWFiaWxpdGllcwoKU3VtbWFyaXplZCBib290c3RyYXBwZWQgcmVsaWFiaWxpdGllcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYm9vdF9kZiA8LSByZWFkLmNzdignL1VzZXJzL3pleW5lcGVua2F2aS9Eb2N1bWVudHMvUG9sZHJhY2tMYWJMb2NhbC9TZWxmX1JlZ3VsYXRpb25fT250b2xvZ3kvRGF0YS9SZXRlc3RfMDktMjctMjAxNy9ib290c3RyYXBfbWVyZ2VkLmNzdicpCgpib290X2RmID0gYm9vdF9kZiAlPiUKICBkcm9wX25hKCkgJT4lCiAgbXV0YXRlKGljYyA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGljYykpLAogICAgICAgICBzcGVhcm1hbiA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHNwZWFybWFuKSksCiAgICAgICAgIGV0YV9zcSA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGV0YV9zcSkpLAogICAgICAgICBzZW0gPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihzZW0pKSkgCgpib290X2RmID0gYm9vdF9kZltib290X2RmJGR2ICVpbiUgcmV0ZXN0X3JlcG9ydF92YXJzLF0KCiMgcmV0ZXN0X3JlcG9ydF92YXJzW3doaWNoKHJldGVzdF9yZXBvcnRfdmFycyAlaW4lIGJvb3RfZGYkZHY9PUZBTFNFKV0KCmJvb3RfZGYgJT4lCiAgZ3JvdXBfYnkoZHYpICU+JQogIHN1bW1hcmlzZShpY2NfbWVkaWFuID0gcXVhbnRpbGUoaWNjLCBwcm9icyA9IDAuNSksCiAgICAgICAgICAgIGljY18yLjUgPSBxdWFudGlsZShpY2MsIHByb2JzID0gMC4wMjUpLAogICAgICAgICAgICBpY2NfOTcuNSA9IHF1YW50aWxlKGljYywgcHJvYnMgPSAwLjk3NSksCiAgICAgICAgICAgIHNwZWFybWFuX21lZGlhbiA9IHF1YW50aWxlKHNwZWFybWFuLCBwcm9icyA9IDAuNSksCiAgICAgICAgICAgIHNwZWFybWFuXzIuNSA9IHF1YW50aWxlKHNwZWFybWFuLCBwcm9icyA9IDAuMDI1KSwKICAgICAgICAgICAgc3BlYXJtYW5fOTcuNSA9IHF1YW50aWxlKHNwZWFybWFuLCBwcm9icyA9IDAuOTc1KSkgJT4lCiAgZGF0YXRhYmxlKCkgJT4lCiAgZm9ybWF0Um91bmQoY29sdW1ucz1jKCdpY2NfbWVkaWFuJywgJ2ljY18yLjUnLCAnaWNjXzk3LjUnLCAnc3BlYXJtYW5fbWVkaWFuJywgJ3NwZWFybWFuXzIuNScsICdzcGVhcm1hbl85Ny41JyksIGRpZ2l0cz0zKQpgYGAKCmBgYHtyIGVjaG89RkFMU0V9Cm1lYXN1cmVfbGFiZWxzIDwtIHJlYWQuY3N2KCcvVXNlcnMvemV5bmVwZW5rYXZpL0Ryb3Bib3gvUG9sZHJhY2tMYWIvU1JPX1JldGVzdF9BbmFseXNlcy9pbnB1dC9tZWFzdXJlX2xhYmVscy5jc3YnKQptZWFzdXJlX2xhYmVscyA9IG1lYXN1cmVfbGFiZWxzICU+JSBzZWxlY3QoLW1lYXN1cmVfZGVzY3JpcHRpb24sLW1lYXN1cmVfdHlwZSwtbWVhc3VyZV90eXBlX0lhbiwtbWVhc3VyZV90eXBlX1J1c3MsLW5vdGVzLC1QYXRyaWNrX2hhdGVzKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMgRGYgd3JhbmdsaW5nIGZvciBwbG90dGluZwp0bXAgPSBtZWFzdXJlX2xhYmVscyAlPiUKICBtdXRhdGUoZHYgPSBhcy5jaGFyYWN0ZXIoZHYpKSAlPiUKICBsZWZ0X2pvaW4oYm9vdF9kZlssYygiZHYiLCAiaWNjIiwgInNwZWFybWFuIildLCBieSA9ICdkdicpIAoKdG1wID0gdG1wICU+JQogIHNlcGFyYXRlKGR2LCBjKCJ0YXNrX2dyb3VwIiwgInZhciIpLCBzZXA9IlxcLiIscmVtb3ZlPUZBTFNFLGV4dHJhPSJtZXJnZSIpICU+JQogIG11dGF0ZSh0YXNrX2dyb3VwID0gZmFjdG9yKHRhc2tfZ3JvdXAsIGxldmVscyA9IHRhc2tfZ3JvdXBbb3JkZXIodGFzayldKSkgJT4lCiAgc2VwYXJhdGUodmFyLCBjKCJ2YXIiKSwgc2VwPSJcXC4iLHJlbW92ZT1UUlVFLGV4dHJhPSJkcm9wIikgJT4lCiAgbXV0YXRlKHRhc2tfZ3JvdXAgPSBnc3ViKCJfIiwgIiAiLCB0YXNrX2dyb3VwKSwKICAgICAgICAgdmFyID0gZ3N1YigiXyIsICIgIiwgdmFyKSkgJT4lCiAgYXJyYW5nZSh0YXNrX2dyb3VwLCB2YXIpCgp0bXAgPSB0bXAgJT4lCiAgbGVmdF9qb2luKHJlbF9kZlssYygiZHYiLCAiaWNjIildLCBieSA9ICJkdiIpICU+JQogIHJlbmFtZShpY2MgPSBpY2MueCwgcG9pbnRfZXN0ID0gaWNjLnkpCgojTWFudWFsIGNvcnJlY3Rpb24KdG1wID0gdG1wICU+JQogIG11dGF0ZSh0YXNrID0gaWZlbHNlKHRhc2tfZ3JvdXAgPT0gJ2hvbHQgbGF1cnkgc3VydmV5JywgInRhc2siLCBhcy5jaGFyYWN0ZXIodGFzaykpKSAlPiUKICBtdXRhdGUodGFza19ncm91cCA9IGlmZWxzZSh0YXNrX2dyb3VwID09ICJwc3ljaG9sb2dpY2FsIHJlZnJhY3RvcnkgcGVyaW9kIHR3byBjaG9pY2VzIiwgInBzeWNob2xvZ2ljYWwgcmVmcmFjdG9yeSBwZXJpb2QiLCBpZmVsc2UodGFza19ncm91cCA9PSAiYW5nbGluZyByaXNrIHRhc2sgYWx3YXlzIHN1bm55IiwgImFuZ2xpbmcgcmlzayB0YXNrIix0YXNrX2dyb3VwKSkpICU+JQogIG11dGF0ZSh0YXNrX2dyb3VwID0gZ3N1Yigic3VydmV5IiwgIiIsIHRhc2tfZ3JvdXApKQpgYGAKClZhcmlhYmxlIGxldmVsIHN1bW1hcnkgb2YgYm9vdHN0cmFwcGVkIHJlbGlhYmlsaXRpZXMuCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfSAKcDQgPC0gdG1wICU+JQogIGZpbHRlcih0YXNrID09ICd0YXNrJywKICAgICAgICAgcmF3X2ZpdCA9PSAncmF3JykgJT4lCmdncGxvdChhZXMoeSA9IHZhciwgeCA9IGljYykpICsgCiAgZ2VvbV9wb2ludChjb2xvciA9ICcjMDBCRkM0JykrCiAgZ2VvbV9wb2ludChhZXMoeSA9IHZhciwgeCA9IHBvaW50X2VzdCksIGNvbG9yID0gImJsYWNrIikrCiAgZmFjZXRfZ3JpZCh0YXNrX2dyb3Vwfi4sIHN3aXRjaCA9ICJ5Iiwgc2NhbGVzID0gImZyZWVfeSIsIHNwYWNlID0gImZyZWVfeSIsIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGg9MjApKSArCiAgdGhlbWUocGFuZWwuc3BhY2luZyA9IHVuaXQoMC43NSwgImxpbmVzIiksIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGU9MTgwLCBzaXplPTM2KSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTgwIikpICsgCiAgeGxhYigiIikrCiAgeWxhYigiIikrCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTAuMjUsMSksIGJyZWFrcz1jKC0wLjI1LCAwLCAwLjI1LCAwLjUsIDAuNzUsIDEpKSsKICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHN0cl93cmFwKHgsIHdpZHRoID0gMTApKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMSkKCnA1IDwtIHRtcCAlPiUKICBmaWx0ZXIodGFzayA9PSAnc3VydmV5JykgJT4lCmdncGxvdChhZXMoeSA9IHZhciwgeCA9IGljYykpICsgCiAgZ2VvbV9wb2ludChjb2xvciA9ICcjRjg3NjZEJykrCiAgZ2VvbV9wb2ludChhZXMoeSA9IHZhciwgeCA9IHBvaW50X2VzdCksIGNvbG9yID0gImJsYWNrIikrCiAgZmFjZXRfZ3JpZCh0YXNrX2dyb3Vwfi4sIHN3aXRjaCA9ICJ5Iiwgc2NhbGVzID0gImZyZWVfeSIsIHNwYWNlID0gImZyZWVfeSIsIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGg9MjApKSArCiAgdGhlbWUocGFuZWwuc3BhY2luZyA9IHVuaXQoMC43NSwgImxpbmVzIiksIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGU9MTgwLCBzaXplPTM2KSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTgwIikpICsgCiAgeGxhYigiIikrCiAgeWxhYigiIikrCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTAuMjUsMSksIGJyZWFrcz1jKC0wLjI1LCAwLCAwLjI1LCAwLjUsIDAuNzUsIDEpKSsKICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHN0cl93cmFwKHgsIHdpZHRoID0gMTApKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMSkKICAKcDYgPC0gYXJyYW5nZUdyb2IocDQsIHA1LG5yb3c9MSkKCmdnc2F2ZSgnQm9vdHN0cmFwX1Jhd19WYXJfUGxvdC5qcGcnLCBwbG90ID0gcDYsIGRldmljZSA9ICJqcGVnIiwgcGF0aCA9ICIvVXNlcnMvemV5bmVwZW5rYXZpL0Ryb3Bib3gvUG9sZHJhY2tMYWIvU1JPX1JldGVzdF9BbmFseXNlcy9vdXRwdXQvZmlndXJlcy8iLCB3aWR0aCA9IDM2LCBoZWlnaHQgPSA3MiwgdW5pdHMgPSAiaW4iLCBsaW1pdHNpemUgPSBGQUxTRSwgZHBpPTUwKQoKcm0ocDQsIHA1LCBwNikKYGBgCgpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzEwMCUnfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnL1VzZXJzL3pleW5lcGVua2F2aS9Ecm9wYm94L1BvbGRyYWNrTGFiL1NST19SZXRlc3RfQW5hbHlzZXMvb3V0cHV0L2ZpZ3VyZXMvQm9vdHN0cmFwX1Jhd19WYXJfUGxvdC5qcGcnKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnA0X3QgPC0gdG1wICU+JQogIGZpbHRlcih0YXNrID09ICd0YXNrJykgJT4lCmdncGxvdChhZXMoeCA9IGZhY3Rvcih0YXNrX2dyb3VwLCBsZXZlbHM9cmV2KHVuaXF1ZSh0YXNrX2dyb3VwKSkpLCB5ID0gaWNjKSkgKyAKICBnZW9tX3Zpb2xpbihmaWxsPScjMDBCRkM0JykrCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MzApKSsKICB4bGFiKCIiKSsKICB5bGFiKCIiKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC4yNSwxKSwgYnJlYWtzPWMoLTAuMjUsIDAsIDAuMjUsIDAuNSwgMC43NSwgMSkpKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gZnVuY3Rpb24oeCkgc3RyX3dyYXAoeCwgd2lkdGggPSAxNSkpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZCIsIHNpemUgPSAxKSsKICBjb29yZF9mbGlwKCkKCnA1X3QgPC0gdG1wICU+JQogIGZpbHRlcih0YXNrID09ICdzdXJ2ZXknKSAlPiUKZ2dwbG90KGFlcyh4ID0gZmFjdG9yKHRhc2tfZ3JvdXAsIGxldmVscz1yZXYodW5pcXVlKHRhc2tfZ3JvdXApKSksIHkgPSBpY2MpKSArIAogIGdlb21fdmlvbGluKGZpbGw9JyNGODc2NkQnKSsKICB0aGVtZV9idygpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT00MykpKwogIHhsYWIoIiIpKwogIHlsYWIoIiIpKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0wLjI1LDEpLCBicmVha3M9YygtMC4yNSwgMCwgMC4yNSwgMC41LCAwLjc1LCAxKSkrCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJfd3JhcCh4LCB3aWR0aCA9IDEwKSkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDEpKwogIGNvb3JkX2ZsaXAoKQogIApwNl90IDwtIGFycmFuZ2VHcm9iKHA0X3QsIHA1X3QsbnJvdz0xKQoKZ2dzYXZlKCdCb290c3RyYXBfUG9zdGVyX1Bsb3RfdC5qcGcnLCBwbG90ID0gcDZfdCwgZGV2aWNlID0gImpwZWciLCBwYXRoID0gIi4uL291dHB1dC9maWd1cmVzLyIsIHdpZHRoID0gMjcsIGhlaWdodCA9IDQ4LCB1bml0cyA9ICJpbiIsIGxpbWl0c2l6ZSA9IEZBTFNFKQpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCcvVXNlcnMvemV5bmVwZW5rYXZpL0Ryb3Bib3gvUG9sZHJhY2tMYWIvU1JPX1JldGVzdF9BbmFseXNlcy9vdXRwdXQvZmlndXJlcy9Cb290c3RyYXBfUG9zdGVyX1Bsb3RfdC5qcGcnKQpgYGAKCmBgYHtyIGVjaG89RkFMU0V9CnJtKHA0X3QsIHA1X3QsIHA2X3QpCmBgYAoKIyMgU3VydmV5IHZzIFRhc2tzCgpDb21wYXJpc29uIG9mIHN1cnZleSBtZWFzdXJlcyB0byBjb2duaXRpdmUgdGFzayBtZWFzdXJlcyBpbiB0aGUgYm9vdHN0cmFwcGVkIHJlc3VsdHMuIE11bHRpbGV2ZWwgbW9kZWwgd2l0aCByYW5kb20gaW50ZXJjZXB0cyBmb3IgZWFjaCBtZWFzdXJlIGFuZCBmaXhlZCBlZmZlY3Qgb2Ygc3VydmV5IHZlcnN1cyBjb2duaXRpdmUgbWVhc3VyZS4gCgpgYGB7cn0KYm9vdF9kZiA9IGJvb3RfZGYgJT4lCiAgICBtdXRhdGUodGFzayA9IGlmZWxzZShncmVwbCgic3VydmV5IixkdiksICJzdXJ2ZXkiLCJ0YXNrIiksCiAgICAgICAgICAgdGFzayA9IGlmZWxzZShncmVwbCgiaG9sdCIsZHYpLCAidGFzayIsIHRhc2spKQoKYm9vdF9kZiAlPiUKICBncm91cF9ieSh0YXNrKSAlPiUKICBzdW1tYXJpc2UoaWNjX21lZGlhbiA9IHF1YW50aWxlKGljYywgcHJvYnMgPSAwLjUpLAogICAgICAgICAgICBpY2NfMi41ID0gcXVhbnRpbGUoaWNjLCBwcm9icyA9IDAuMDI1KSwKICAgICAgICAgICAgaWNjXzk3LjUgPSBxdWFudGlsZShpY2MsIHByb2JzID0gMC45NzUpLAogICAgICAgICAgICBzcGVhcm1hbl9tZWRpYW4gPSBxdWFudGlsZShzcGVhcm1hbiwgcHJvYnMgPSAwLjUpLAogICAgICAgICAgICBzcGVhcm1hbl8yLjUgPSBxdWFudGlsZShzcGVhcm1hbiwgcHJvYnMgPSAwLjAyNSksCiAgICAgICAgICAgIHNwZWFybWFuXzk3LjUgPSBxdWFudGlsZShzcGVhcm1hbiwgcHJvYnMgPSAwLjk3NSksCiAgICAgICAgICAgIG51bV92YXJzID0gbigpLzEwMDApICU+JQogIGRhdGF0YWJsZSgpICU+JQogIGZvcm1hdFJvdW5kKGNvbHVtbnM9YygnaWNjX21lZGlhbicsICdpY2NfMi41JywgJ2ljY185Ny41JywgJ3NwZWFybWFuX21lZGlhbicsICdzcGVhcm1hbl8yLjUnLCAnc3BlYXJtYW5fOTcuNScpLCBkaWdpdHM9MykKYGBgCgoKYGBge3J9CnN1bW1hcnkobG1lclRlc3Q6OmxtZXIoaWNjIH4gIHRhc2sgKyAoMXxkdiksIGJvb3RfZGYpKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmJvb3RfZGYgJT4lCiAgZ2dwbG90KGFlcyhpY2MsIGZpbGwgPSB0YXNrKSkrCiAgZ2VvbV9oaXN0b2dyYW0oYWxwaGE9MC41LCBwb3NpdGlvbj0naWRlbnRpdHknKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgeGxhYigiSUNDIikKCmdnc2F2ZSgnSGlzdF9Cb290X1JlbC5qcGcnLCBkZXZpY2UgPSAianBlZyIsIHBhdGggPSAiL1VzZXJzL3pleW5lcGVua2F2aS9Ecm9wYm94L1BvbGRyYWNrTGFiL1NST19SZXRlc3RfQW5hbHlzZXMvb3V0cHV0L2ZpZ3VyZXMvIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCB1bml0cyA9ICJpbiIsIGxpbWl0c2l6ZSA9IEZBTFNFLCBkcGkgPSA3MikKYGBgCgojIyMgVmFyaWFuY2UgYnJlYWtkb3duCgpUaGUgcXVhbnRpYXRpdmUgZXhwbGFuYXRpb24gZm9yIHRoZSBkaWZmZXJlbmNlIGluIHJlbGlhYmlsaXR5IGVzdGltYXRlcyBiZXR3ZWVuIHN1cnZleXMgYW5kIHRhc2tzLCBhcyByZWNlbnRseSBkZXRhaWxlZCBieSBIZWRnZSBldCBhbC4gKDIwMTcpLCBsaWVzIGluIHRoZSBkaWZmZXJlbmNlIGluIHNvdXJjZXMgb2YgdmFyaWFuY2UgYmV0d2VlbiB0aGVzZSBtZWFzdXJlcy4gVGhpcyBpcyBiZWNhdXNlIHJlbGlhYmlsaXR5IGlzIGVzdGltYXRlZCBhcyBhIHJhdGlvIG9mIHRoZXNlIHNvdXJjZXMgdmFyaWFuY2UgdG8gZWFjaCBvdGhlci4gU3BlY2lmaWNhbGx5LCB0aGUgSUNDIGlzIGNhbGN1bGF0ZWQgYXMgdGhlIHJhdGlvIG9mIHZhcmlhbmNlIGJldHdlZW4gc3ViamVjdHMgdmFyaWFuY2UgdG8gYWxsIHNvdXJjZXMgb2YgdmFyaWFuY2UuIFRodXMsIG1lYXN1cmVzIHdpdGggaGlnaCBiZXR3ZWVuIHN1YmplY3RzIHZhcmlhbmNlIHdvdWxkIGhhdmUgaGlnaCB0ZXN0LXJldGVzdCByZWxpYWJpbGl0eS4gSW50dWl0aXZlbHksIG1lYXN1cmVzIHdpdGggaGlnaCBiZXR3ZWVuIHN1YmplY3RzIHZhcmlhbmNlIGFyZSBhbHNvIGJldHRlciBzdWl0ZWQgZm9yIGluZGl2aWR1YWwgZGlmZmVyZW5jZSBhbmFseXNlcyBhcyB0aGV5IHdvdWxkIGNhcHR1cmUgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHN1YmplY3RzIGluIGEgc2FtcGxlLgoKSGVyZSB3ZSBmaXJzdCBwbG90IHRoZSBwZXJjZW50YWdlIG9mIHZhcmlhbmNlIGV4cGxhaW5lZCBieSB0aGUgdGhyZWUgc291cmNlcyBvZiB2YXJpYW5jZSBmb3IgdGhlIHBvaW50IGVzdGltYXRlcyBvZiBtZWFzdXJlIHJlbGlhYmlsaXRpZXMuIFRoZSBwbG90IG9ubHkgaW5jbHVkZXMgcmF3IG1lYXN1cmVzIChubyBERE0gcGFyYW1ldGVycykgYW5kIHRoZSBtZWFzdXJlcyBhcmUgcmFua2VkIGJ5IHBlcmNlbnRhZ2Ugb2YgYmV0d2VlbiBzdWJqZWN0IHZhcmlhYmlsaXR5IGZvciBlYWNoIHRhc2svc3VydmV5IChpLmUuIHRoZSBiZXN0IHRvIHdvcnN0IGluZGl2aWR1YWwgZGlmZmVyZW5jZSBtZWFzdXJlIGZvciBlYWNoIHRhc2svc3VydmV5KS4gVGhlbiB3ZSBjb21wYXJlIHN0YXRpc3RpY2FsbHkgd2hldGhlciB0aGUgcGVyY2VudGFnZSBvZiB2YXJpYW5jZSBleHBsYWluZWQgYnkgdGhlc2Ugc291cmNlcyBkaWZmZXIgYmV0d2VlbiB0YXNrcyBhbmQgc3VydmV5cy4KCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnRtcCA9IHJlbF9kZiAlPiUKICBtdXRhdGUodmFyX3N1YnNfcGN0ID0gdmFyX3N1YnMvKHZhcl9zdWJzK3Zhcl9pbmQrdmFyX3Jlc2lkKSoxMDAsCiAgICAgICAgIHZhcl9pbmRfcGN0ID0gdmFyX2luZC8odmFyX3N1YnMrdmFyX2luZCt2YXJfcmVzaWQpKjEwMCwgCiAgICAgICAgIHZhcl9yZXNpZF9wY3QgPSB2YXJfcmVzaWQvKHZhcl9zdWJzK3Zhcl9pbmQrdmFyX3Jlc2lkKSoxMDApICU+JQogIHNlbGVjdChkdiwgdGFzaywgdmFyX3N1YnNfcGN0LCB2YXJfaW5kX3BjdCwgdmFyX3Jlc2lkX3BjdCkgJT4lCiAgbXV0YXRlKGR2ID0gZmFjdG9yKGR2LCBsZXZlbHMgPSBkdltvcmRlcih0YXNrKV0pKSAlPiUKICBzZXBhcmF0ZShkdiwgYygidGFza19ncm91cCIsICJ2YXIiKSwgc2VwPSJcXC4iLHJlbW92ZT1GQUxTRSxleHRyYT0ibWVyZ2UiKSAlPiUKICBtdXRhdGUodGFza19ncm91cCA9IGZhY3Rvcih0YXNrX2dyb3VwLCBsZXZlbHMgPSB0YXNrX2dyb3VwW29yZGVyKHRhc2spXSkpICU+JQogIGFycmFuZ2UodGFza19ncm91cCwgdmFyX3N1YnNfcGN0KSAlPiUKICBtdXRhdGUocmFuayA9IHJvd19udW1iZXIoKSkgJT4lCiAgYXJyYW5nZSh0YXNrLCB0YXNrX2dyb3VwLCByYW5rKSAlPiUKICBnYXRoZXIoa2V5LCB2YWx1ZSwgLWR2LCAtdGFza19ncm91cCwgLXZhciwgLXRhc2ssIC1yYW5rKSAlPiUKICB1bmdyb3VwKCklPiUKICBtdXRhdGUodGFza19ncm91cCA9IGdzdWIoIl8iLCAiICIsIHRhc2tfZ3JvdXApLAogICAgICAgICB2YXIgPSBnc3ViKCJfIiwgIiAiLCB2YXIpKSAlPiUKICBtdXRhdGUodGFza19ncm91cCA9IGlmZWxzZSh0YXNrX2dyb3VwID09ICJwc3ljaG9sb2dpY2FsIHJlZnJhY3RvcnkgcGVyaW9kIHR3byBjaG9pY2VzIiwgInBzeWNob2xvZ2ljYWwgcmVmcmFjdG9yeSBwZXJpb2QiLCBpZmVsc2UodGFza19ncm91cCA9PSAiYW5nbGluZyByaXNrIHRhc2sgYWx3YXlzIHN1bm55IiwgImFuZ2xpbmcgcmlzayB0YXNrIix0YXNrX2dyb3VwKSkpICU+JQogIG11dGF0ZSh0YXNrX2dyb3VwID0gZ3N1Yigic3VydmV5IiwgIiIsIHRhc2tfZ3JvdXApKSAlPiUKICBmaWx0ZXIodGFzaz09InRhc2siLAogICAgICAgICAhZ3JlcGwoIkVafGhkZG0iLCBkdikpJT4lCiAgYXJyYW5nZSh0YXNrX2dyb3VwLCByYW5rKQpsYWJlbHMgPSB0bXAgJT4lCiAgZGlzdGluY3QoZHYsIC5rZWVwX2FsbD1UKQoKcDEgPC0gdG1wICU+JQogIGdncGxvdChhZXMoeD1mYWN0b3IocmFuayksIHk9dmFsdWUsIGZpbGw9ZmFjdG9yKGtleSwgbGV2ZWxzID0gYygidmFyX3Jlc2lkX3BjdCIsICJ2YXJfaW5kX3BjdCIsICJ2YXJfc3Vic19wY3QiKSkpKSsKICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScsIGFscGhhID0gMC43NSwgY29sb3I9JyMwMEJGQzQnKSsKICBzY2FsZV94X2Rpc2NyZXRlKGJyZWFrcyA9IGxhYmVscyRyYW5rLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGxhYmVscyR2YXIpKwogIGNvb3JkX2ZsaXAoKSsKICBmYWNldF9ncmlkKHRhc2tfZ3JvdXB+Liwgc3dpdGNoID0gInkiLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3BhY2UgPSAiZnJlZV95IikgKwogIHRoZW1lKHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGU9MTgwKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTg1IiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScpKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgc2NhbGVfZmlsbF9tYW51YWwoYnJlYWtzID0gYygidmFyX3N1YnNfcGN0IiwgInZhcl9pbmRfcGN0IiwgInZhcl9yZXNpZF9wY3QiKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlZhcmlhbmNlIGJldHdlZW4gaW5kaXZpZHVhbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmFyaWFuY2UgYmV0d2VlbiBzZXNzaW9ucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFcnJvciB2YXJpYW5jZSIpLAogICAgICAgICAgICAgICAgICB2YWx1ZXM9YygiZ3JleTY1IiwgImdyZXk0NSIsICJncmV5MjUiKSkrCiAgeWxhYigiIikrCiAgeGxhYigiIikKCnRtcCA9IHJlbF9kZiAlPiUKICBtdXRhdGUodmFyX3N1YnNfcGN0ID0gdmFyX3N1YnMvKHZhcl9zdWJzK3Zhcl9pbmQrdmFyX3Jlc2lkKSoxMDAsCiAgICAgICAgIHZhcl9pbmRfcGN0ID0gdmFyX2luZC8odmFyX3N1YnMrdmFyX2luZCt2YXJfcmVzaWQpKjEwMCwgCiAgICAgICAgIHZhcl9yZXNpZF9wY3QgPSB2YXJfcmVzaWQvKHZhcl9zdWJzK3Zhcl9pbmQrdmFyX3Jlc2lkKSoxMDApICU+JQogIHNlbGVjdChkdiwgdGFzaywgdmFyX3N1YnNfcGN0LCB2YXJfaW5kX3BjdCwgdmFyX3Jlc2lkX3BjdCkgJT4lCiAgbXV0YXRlKGR2ID0gZmFjdG9yKGR2LCBsZXZlbHMgPSBkdltvcmRlcih0YXNrKV0pKSAlPiUKICBzZXBhcmF0ZShkdiwgYygidGFza19ncm91cCIsICJ2YXIiKSwgc2VwPSJcXC4iLHJlbW92ZT1GQUxTRSxleHRyYT0ibWVyZ2UiKSAlPiUKICBtdXRhdGUodGFza19ncm91cCA9IGZhY3Rvcih0YXNrX2dyb3VwLCBsZXZlbHMgPSB0YXNrX2dyb3VwW29yZGVyKHRhc2spXSkpICU+JQogIGFycmFuZ2UodGFza19ncm91cCwgdmFyX3N1YnNfcGN0KSAlPiUKICBtdXRhdGUocmFuayA9IHJvd19udW1iZXIoKSkgJT4lCiAgYXJyYW5nZSh0YXNrLCB0YXNrX2dyb3VwLCByYW5rKSAlPiUKICBnYXRoZXIoa2V5LCB2YWx1ZSwgLWR2LCAtdGFza19ncm91cCwgLXZhciwgLXRhc2ssIC1yYW5rKSAlPiUKICB1bmdyb3VwKCklPiUKICBtdXRhdGUodGFza19ncm91cCA9IGdzdWIoIl8iLCAiICIsIHRhc2tfZ3JvdXApLAogICAgICAgICB2YXIgPSBnc3ViKCJfIiwgIiAiLCB2YXIpKSAlPiUKICBtdXRhdGUodGFza19ncm91cCA9IGlmZWxzZSh0YXNrX2dyb3VwID09ICJwc3ljaG9sb2dpY2FsIHJlZnJhY3RvcnkgcGVyaW9kIHR3byBjaG9pY2VzIiwgInBzeWNob2xvZ2ljYWwgcmVmcmFjdG9yeSBwZXJpb2QiLCBpZmVsc2UodGFza19ncm91cCA9PSAiYW5nbGluZyByaXNrIHRhc2sgYWx3YXlzIHN1bm55IiwgImFuZ2xpbmcgcmlzayB0YXNrIix0YXNrX2dyb3VwKSkpICU+JQogIG11dGF0ZSh0YXNrX2dyb3VwID0gZ3N1Yigic3VydmV5IiwgIiIsIHRhc2tfZ3JvdXApKSAlPiUKICBmaWx0ZXIodGFzaz09InN1cnZleSIpJT4lCiAgYXJyYW5nZSh0YXNrX2dyb3VwLCByYW5rKQpsYWJlbHMgPSB0bXAgJT4lCiAgZGlzdGluY3QoZHYsIC5rZWVwX2FsbD1UKQoKcDIgPC0gdG1wICU+JQogIGdncGxvdChhZXMoeD1mYWN0b3IocmFuayksIHk9dmFsdWUsIGZpbGw9ZmFjdG9yKGtleSwgbGV2ZWxzID0gYygidmFyX3Jlc2lkX3BjdCIsICJ2YXJfaW5kX3BjdCIsICJ2YXJfc3Vic19wY3QiKSkpKSsKICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScsIGFscGhhID0gMC43NSkrCiAgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknLCBjb2xvcj0nI0Y4NzY2RCcsIHNob3cubGVnZW5kPUZBTFNFKSsKICBzY2FsZV94X2Rpc2NyZXRlKGJyZWFrcyA9IGxhYmVscyRyYW5rLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGxhYmVscyR2YXIpKwogIGNvb3JkX2ZsaXAoKSsKICBmYWNldF9ncmlkKHRhc2tfZ3JvdXB+Liwgc3dpdGNoID0gInkiLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3BhY2UgPSAiZnJlZV95IikgKwogIHRoZW1lKHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNSwgImxpbmVzIiksIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwKICAgICAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGU9MTgwKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTg1IiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScpKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgc2NhbGVfZmlsbF9tYW51YWwoYnJlYWtzID0gYygidmFyX3N1YnNfcGN0IiwgInZhcl9pbmRfcGN0IiwgInZhcl9yZXNpZF9wY3QiKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlZhcmlhbmNlIGJldHdlZW4gaW5kaXZpZHVhbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmFyaWFuY2UgYmV0d2VlbiBzZXNzaW9ucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFcnJvciB2YXJpYW5jZSIpLAogICAgICAgICAgICAgICAgICB2YWx1ZXM9YygiZ3JleTY1IiwgImdyZXk0NSIsICJncmV5MjUiKSkrCiAgeWxhYigiIikrCiAgeGxhYigiIikKCm15bGVnZW5kPC1nX2xlZ2VuZChwMikKCnAzIDwtIGFycmFuZ2VHcm9iKGFycmFuZ2VHcm9iKHAxICt0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHAyICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksCiAgICAgICAgICAgICAgICAgICAgICAgICBucm93PTEpLAogICAgICAgICAgICAgbXlsZWdlbmQsIG5yb3c9MixoZWlnaHRzPWMoMTAsIDEpKQoKZ2dzYXZlKCdWYXJpYW5jZV9CcmVha2Rvd25fUGxvdC5qcGcnLCBwbG90ID0gcDMsIGRldmljZSA9ICJqcGVnIiwgcGF0aCA9ICIvVXNlcnMvemV5bmVwZW5rYXZpL0Ryb3Bib3gvUG9sZHJhY2tMYWIvU1JPX1JldGVzdF9BbmFseXNlcy9vdXRwdXQvZmlndXJlcyIsIHdpZHRoID0gMjQsIGhlaWdodCA9IDIwLCB1bml0cyA9ICJpbiIpCnJtKHRtcCwgbGFiZWxzKQpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCcvVXNlcnMvemV5bmVwZW5rYXZpL0Ryb3Bib3gvUG9sZHJhY2tMYWIvU1JPX1JldGVzdF9BbmFseXNlcy9vdXRwdXQvZmlndXJlcy9WYXJpYW5jZV9CcmVha2Rvd25fUGxvdC5qcGcnKQpgYGAKCkNvbXBhcmluZyB0eXBlcyBvZiB2YXJpYW5jZSBmb3Igc3VydmV5IHZzIHRhc2sgbWVhc3VyZXM6IFN1cnZleSBtZWFzdXJlcyBoYXZlIGhpZ2hlciBiZXR3ZWVuIHN1YmplY3QgdmFyaWFiaWxpdHkgIAoKTm90ZTogVGhpcyBhbmFseXNpcyBpbmNsdWRlcyBERE0gdmFyaWFibGVzIHRvby4KCmBgYHtyfQp0bXAgPSBib290X2RmICU+JQogIG11dGF0ZSh2YXJfc3Vic19wY3QgPSB2YXJfc3Vicy8odmFyX3N1YnMrdmFyX2luZCt2YXJfcmVzaWQpKjEwMCwKICAgICAgICAgdmFyX2luZF9wY3QgPSB2YXJfaW5kLyh2YXJfc3Vicyt2YXJfaW5kK3Zhcl9yZXNpZCkqMTAwLCAKICAgICAgICAgdmFyX3Jlc2lkX3BjdCA9IHZhcl9yZXNpZC8odmFyX3N1YnMrdmFyX2luZCt2YXJfcmVzaWQpKjEwMCkgJT4lCiAgc2VsZWN0KGR2LCB0YXNrLCB2YXJfc3Vic19wY3QsIHZhcl9pbmRfcGN0LCB2YXJfcmVzaWRfcGN0KSAlPiUKICBnYXRoZXIoa2V5LCB2YWx1ZSwgLWR2LCAtdGFzaykgCgpzdW1tYXJ5KGxtZXIodmFsdWV+a2V5KnRhc2srKDF8ZHYpLHRtcCkpCmBgYAoKYGBge3J9CmFnZ3JlZ2F0ZSh2YWx1ZSB+dGFzaytrZXksIEZVTj1tZWFuLCBkYXRhPXRtcCkKCnRtcCU+JQogIGdyb3VwX2J5KHRhc2ssIGtleSkgJT4lCiAgc3VtbWFyaXNlKG1lZGlhbiA9IG1lZGlhbih2YWx1ZSksCiAgICAgICAgICAgIHNkID0gc2QodmFsdWUpKQpgYGAKClN1bW1hcml6aW5nIGZvciBjbGVhcmVyIHByZXNlbnRhdGlvbi4gVGhpcyBncmFwIGlzIGN1cnJlbnRseSB1c2luZyB0aGUgYm9vdHN0cmFwcGVkIHJlbGlhYmlsaXRpZXMgYW5kIGlzIHRoZXJlZm9yZSBtZXNzaWVyIHRoYW4gaWYganVzdCB1c2luZyB0aGUgcG9pbnQgZXN0aW1hdGVzLgoKYGBge3J9CnRtcCAlPiUKICBncm91cF9ieSh0YXNrLCBrZXkpICU+JQogIGdncGxvdChhZXMoZmFjdG9yKHRhc2ssIGxldmVscz1jKCJ0YXNrIiwic3VydmV5IiksIGxhYmVscz1jKCJUYXNrIiwgIlN1cnZleSIpKSwgdmFsdWUsIGZpbGw9a2V5LCBjb2xvcj10YXNrKSkrCiAgZ2VvbV9ib3hwbG90KCkrCiAgdGhlbWVfYncoKSsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogIHNjYWxlX2ZpbGxfbWFudWFsKGJyZWFrcyA9IGMoInZhcl9zdWJzX3BjdCIsICJ2YXJfaW5kX3BjdCIsICJ2YXJfcmVzaWRfcGN0IiksCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiVmFyaWFuY2UgYmV0d2VlbiBpbmRpdmlkdWFscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmFyaWFuY2UgYmV0d2VlbiBzZXNzaW9ucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRXJyb3IgdmFyaWFuY2UiKSwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9YygiZ3JleTY1IiwgImdyZXk0NSIsICJncmV5MjUiKSkrCiAgc2NhbGVfY29sb3JfZGlzY3JldGUoZ3VpZGUgPSBGQUxTRSkrCiAgeGxhYigiIikrCiAgeWxhYigiUGVyY2VudCIpCgpnZ3NhdmUoJ1ZhcmlhbmNlX0JyZWFrZG93bl9QbG90X1N1bW1hcnkuanBnJywgZGV2aWNlID0gImpwZWciLCBwYXRoID0gIi9Vc2Vycy96ZXluZXBlbmthdmkvRHJvcGJveC9Qb2xkcmFja0xhYi9TUk9fUmV0ZXN0X0FuYWx5c2VzL291dHB1dC9maWd1cmVzIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSwgdW5pdHMgPSAiaW4iKQpgYGAKCiMjIFRhc2sgUmVsaWFiaWxpdGllcwoKSGVyZSB3ZSBzdW1tYXJpemUgdGhlIHJlc3VsdHMgb24gYSB0YXNrIGxldmVsIHRvIG1ha2UgaXQgbW9yZSBkaWdlc3RhYmxlIGFuZCBlYXNpZXIgdG8gbWFrZSBjb250YWN0IHdpdGggdGhlIGxpdGVyYXR1cmUuICAKCldlIHJlZHVjZSB0aGUgbGlzdCBvZiB0YXNrIG1lYXN1cmVzIHRvIGEgbGlzdCBvZiBvbmUgcGVyIHRhc2sgYnkgYXZlcmFnaW5nIG9ubHkgdGhlIHJhdyBtZWFzdXJlcyBmcm9tIGFsbCB0aGUgdHJpYWxzIGluIGEgdGFzay4gV2UgY2hvc2UgdG8gcmVkdWNlIHRoZSBpbmZvcm1hdGlvbiBpbiB0aGlzIG1hbm5lciB0byBhdm9pZCBhbnkgYmlhcyBzdGVtbWluZyBmcm9tIGRpZmZlcmVudGlhbCBhbW91bnQgb2YgaW50ZXJlc3QgYW5kIHByb2NlZHVyZXMgYXBwbGllZCB0byBjZXJ0YWluIHRhc2tzIG92ZXIgb3RoZXJzIChlLmcuIGEgdGFzayBjYW4gaGF2ZSBvdmVyIDEwIG1lYXN1cmVzIGJlY2F1c2UgaXQgaGFzIG11bHRpcGxlIGNvbmRpdGlvbnMgYW5kIHdlIGhhdmUgY2hvc2VuIHRvIGZpdCBERE0ncyBmb3Igc3BlY2lmaWMgY29uZGl0aW9ucyB3aGlsZSBhbm90aGVyIG1pZ2h0IG9ubHkgaGF2ZSAyIGR1ZSB0byBvdXIgcmVsYXRpdmUgaW5leHBlcmllbmNlIGFuZCBsYWNrIG9mIGludGVyZXN0IGluIGl0KS4gV2UgY2hlY2sgd2hldGhlciB0aGUgbnVtYmVyIG9mIHRyaWFscyBpbiBhIHRhc2sgaGFzIGEgc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHRoZXNlIGF2ZXJhZ2UgcmVsaWFiaWxpdGllcyBvZiByYXcgbWVhc3VyZXMgYXMgd2VsbC4gCgpXZSBmaWx0ZXIgb3V0IHRoZSBERE0gcGFyYW1ldGVycyBhbmQgbWVhc3VyZXMgZm9yIHNwZWNpZmljIGNvbnRyYXN0cy4gTm90ZSB0aGF0IHRoaXMgZG9lcyBsZWF2ZSBzb21lIHRhc2tzIHdpdGggbWVhc3VyZXMgdGhhdCBhcmUgbW9kZWwgZml0cyBhbmQvb3IgZm9yIHNwZWNpZmljIGNvbmRpdGlvbnMgKGJlY2F1c2UgYXQgbGVhc3QgdGhlIGN1cnJlbnQgZGF0YXNldHMgZG8gbm90IGluY2x1ZGUgbWVhc3VyZXMgdGhhdCBhcmUgYmFzZWQgb24gYWxsIHRoZSB0cmlhbHMgKiphbmQqKiBhcmUgcmF3IHRob3VnaCBJIGNvdWxkIGRpdmUgaW4gdG8gdmFyaWFibGVzX2V4aGF1c3RpdmUgZm9yIHN1Y2ggbWVhc3VyZXMuIEZvciBleGFtcGxlIHRoZSBhdmVyYWdlIHJlbGlhbGliaWxpdHkgZm9yIEtpcmJ5IGlzIGJhc2VkIG9uIHRocmVlIGRpc2NvdW50IHJhdGVzIGZvciBzcGVjaWZpYyBjb25kaXRpb25zLikuIEhlcmUncyB0aGUgb3JkZXIgb2YgdGFza3MgYnkgbWVhbiByZWxpYWJpbGl0eSBzb3J0ZWQgZm9yIElDQyBhbmQgdGhlbiBTcGVhcm1hbidzICRccmhvJC4KCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnRtcCA9IG1lYXN1cmVfbGFiZWxzICU+JQogIG11dGF0ZShkdiA9IGFzLmNoYXJhY3RlcihkdikpICU+JQogIGZpbHRlcih0YXNrID09ICd0YXNrJykgJT4lCiAgbGVmdF9qb2luKGJvb3RfZGZbLGMoImR2IiwgImljYyIsICJzcGVhcm1hbiIpXSwgYnkgPSAnZHYnKSAlPiUKICBmaWx0ZXIob3ZlcmFsbF9kaWZmZXJlbmNlICE9ICdkaWZmZXJlbmNlJyAmIHJhd19maXQgJWluJSBjKCdFWicsICdoZGRtJykgPT0gRkFMU0UpJT4lCiAgc2VwYXJhdGUoZHYsIGMoJ3Rhc2tfbmFtZScsICdleHRyYV8xJywgJ2V4dHJhXzInKSwgc2VwID0gJ1xcLicscmVtb3ZlPUZBTFNFKSAlPiUKICBzZWxlY3QoLWV4dHJhXzEsIC1leHRyYV8yKSAlPiUKICBncm91cF9ieSh0YXNrX25hbWUpICU+JQogIHN1bW1hcmlzZShtZWRpYW5faWNjID0gbWVkaWFuKGljYyksCiAgICAgICAgICAgIG1lZGlhbl9zcGVhcm1hbiA9IG1lZGlhbihzcGVhcm1hbiksCiAgICAgICAgICAgIG1pbl9pY2MgPSBtaW4oaWNjKSwKICAgICAgICAgICAgbWF4X2ljYyA9IG1heChpY2MpLAogICAgICAgICAgICBtaW5fc3BlYXJtYW4gPSBtaW4oc3BlYXJtYW4pLAogICAgICAgICAgICBtYXhfc3BlYXJtYW4gPSBtYXgoc3BlYXJtYW4pLAogICAgICAgICAgICBudW1fbWVhc3VyZXMgPSBuKCksCiAgICAgICAgICAgIG51bV90cmlhbHMgPSB1bmlxdWUobnVtX2FsbF90cmlhbHMpKSU+JQogIGFycmFuZ2UoLW1lZGlhbl9pY2MsIC1tZWRpYW5fc3BlYXJtYW4pCgp0bXAgJT4lCiAgZGF0YXRhYmxlKCkgJT4lCiAgZm9ybWF0Um91bmQoY29sdW1ucz1jKCdtZWRpYW5fc3BlYXJtYW4nLCAnbWVkaWFuX2ljYycsCiAgICAgICAgICAgICAgICAgICAgICAgICdtaW5fc3BlYXJtYW4nLCAnbWluX2ljYycsCiAgICAgICAgICAgICAgICAgICAgICAgICdtYXhfc3BlYXJtYW4nLCAnbWF4X2ljYycpLCBkaWdpdHM9MykKYGBgCgojIyMgTnVtYmVyIG9mIHRyaWFscwoKRG9lcyBudW1iZXIgb2YgaXRlbXMgaW4gYSB0YXNrIGhhdmUgYSBzaWduaWZpY2FudCBlZmZlY3Qgb24gdGhlIGF2ZXJhZ2UgSUNDIG9mIChtb3N0bHkpIHJhdyBtZWFzdXJlcyBmb3IgYWxsIHRyaWFscyBmcm9tIGEgdGFzaz8gTm8uIChubyBlZmZlY3Qgb24gU3BlYXJtYW4gZWl0aGVyKQoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KdG1wID0gbWVhc3VyZV9sYWJlbHMgJT4lCiAgbXV0YXRlKGR2ID0gYXMuY2hhcmFjdGVyKGR2KSkgJT4lCiAgZmlsdGVyKHRhc2sgPT0gJ3Rhc2snKSAlPiUKICAjIGxlZnRfam9pbihyZWxfZGZbLGMoImR2IiwgInNwZWFybWFuIiwiaWNjIildLCBieT0nZHYnKSAlPiUKICBsZWZ0X2pvaW4oYm9vdF9kZlssYygiZHYiLCAic3BlYXJtYW4iLCJpY2MiKV0sIGJ5PSdkdicpICU+JQogIGZpbHRlcihvdmVyYWxsX2RpZmZlcmVuY2UgIT0gJ2RpZmZlcmVuY2UnICYgcmF3X2ZpdCAlaW4lIGMoJ0VaJywgJ2hkZG0nKSA9PSBGQUxTRSklPiUKICBzZXBhcmF0ZShkdiwgYygndGFza19uYW1lJywgJ2V4dHJhXzEnLCAnZXh0cmFfMicpLCBzZXAgPSAnXFwuJyxyZW1vdmU9RkFMU0UpICU+JQogIHNlbGVjdCgtZXh0cmFfMSwgLWV4dHJhXzIpCgojIHN1bW1hcnkobG0oaWNjIH4gbnVtX2FsbF90cmlhbHMsIGRhdGEgPSB0bXApKQpzdW1tYXJ5KGxtZXIoaWNjIH4gbnVtX2FsbF90cmlhbHMgKyAoMXxkdiksIGRhdGEgPSB0bXApKQpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9Cm1lYXN1cmVfbGFiZWxzICU+JQogIG11dGF0ZShkdiA9IGFzLmNoYXJhY3RlcihkdikpICU+JQogIGZpbHRlcih0YXNrID09ICd0YXNrJykgJT4lCiAgIyBsZWZ0X2pvaW4ocmVsX2RmWyxjKCJkdiIsICJzcGVhcm1hbiIsImljYyIpXSwgYnk9J2R2JykgJT4lCiAgbGVmdF9qb2luKGJvb3RfZGZbLGMoImR2IiwgInNwZWFybWFuIiwiaWNjIildLCBieT0nZHYnKSAlPiUKICBmaWx0ZXIob3ZlcmFsbF9kaWZmZXJlbmNlICE9ICdkaWZmZXJlbmNlJyAmIHJhd19maXQgJWluJSBjKCdFWicsICdoZGRtJykgPT0gRkFMU0UpJT4lCiAgc2VwYXJhdGUoZHYsIGMoJ3Rhc2tfbmFtZScsICdleHRyYV8xJywgJ2V4dHJhXzInKSwgc2VwID0gJ1xcLicscmVtb3ZlPUZBTFNFKSAlPiUKICBzZWxlY3QoLWV4dHJhXzEsIC1leHRyYV8yKSAlPiUKICBnZ3Bsb3QoYWVzKG51bV9hbGxfdHJpYWxzLCBpY2MpKSsKICBnZW9tX3BvaW50KCkrCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpKwogIHRoZW1lX2J3KCkrCiAgeGxhYigiTnVtYmVyIG9mIHRyaWFscyIpKwogIHlsYWIoIklDQyIpCmBgYAoKIyMjIyBUcmlhbCBudW1iZXIgZGVwZW5kZW5jZSBpbnRyYW1lYXN1cmUgCgpUaGUgYWJvdmUgYW5hbHlzaXMgd2FzIGxvb2tpbmcgYXQgdGhlIGVmZmVjdCBvZiBudW1iZXIgb2YgdHJpYWxzIGFjcm9zcyB0YXNrcy4gQnV0IHNvbWUgdGFza3MgbWlnaHQgYmUgYmFkIGZvciBpbmRpdmlkdWFsIGRpZmZlcmVuY2UgbWVhc3VyZW1lbnQgcmVnYXJkbGVzcyBvZiBob3cgbWFueSB0cmlhbHMgdGhlcmUgYXJlIGluIHRoZW0gd2hlcmVhcyBmb3Igb3RoZXJzIGZld2VyIHRyaWFscyBtaWdodCBiZSB5aWVsZGluZyBhIHN1ZmZpY2llbnRseSByZWxpYWJsZSBtZWFzdXJlLgoKRm9yIHRhc2tzIGZvciB3aGljaCBkZXBlbmRlbnQgdmFyaWFibGVzIGFyZSBlc3RpbWF0ZWQgdXNpbmcgbWFueSB0cmlhbHMgb25lIGNhbiBhc2s6IERvZXMgdGhlIHNhbWUgbWVhc3VyZSBnZXQgbGVzcyByZWxpYWJsZSBpZiBmZXdlciB0cmlhbHMgYXJlIHVzZWQgdG8gZXN0aW1hdGUgaXRzIHJlbGlhYmlsaXR5PwoKVGhpcyB3b24ndCBtYWtlIHNlbnNlIGZvciBhbGwgdGFza3MuIEZvciBleGFtcGxlIHRvIGVzdGltYXRlIGEgcmlzayBhdmVyc2lvbiBwYXJhbWV0ZXIgeW91IG5lZWQgYWxsIHRyaWFscyBmb3IgSG9sdCBhbmQgTGF1cnkuIEZvciBLaXJieSBhbmQgQmlja2VsIHlvdSBoYXZlIHNwZWNpZmljIGNvbmRpdGlvbnMgbG9va2luZyBhdCBmZXdlciB0cmlhbHMuIFRoZSBDb2duaXRpdmUgUmVmbGVjdGlvbiBUYXNrIG1pZ2h0IGJlIG1vcmUgYXBwcm9wcmlhdGUgdG8gYW5hbHl6ZSBlYWNoIGl0ZW0gc2VhcHJhdGVseS4gVGhlIHdyaXRpbmcgdGFzayBkb2VzIG5vdCBoYXZlIHRyaWFsIG51bWJlcnMuIEZvciBhbGwgb3RoZXJzIGl0IG1pZ2h0IGJlIGludGVyZXN0aW5nIHRvIGludmVzdGlnYXRlLgoKVGhhdCBzYWlkIHRoaXMga2luZCBvZiBhbmFseXNpcyBzZWVtcyB0b28gaW4gdGhlIHdlZWRzIGZvciBhIHBhcGVyIHRoYXQgaXMgdHJ5aW5nIHRvIGdpdmUgYSBnbG9iYWwgc2Vuc2Ugb2YgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gc2VsZi1yZWd1bGF0aW9uIG1lYXN1cmVzIGluIHRoZWlyIHN1aXRhYmxpdHkgZm9yIGluZGl2aWR1YWwgZGlmZmVyZW5jZSBhbmFseXNlcyBiYXNlZCBvbiB0aGVpciBzdGFiaWxpdHkgYWNyb3NzIHRpbWUuIFN1Y2ggYW5hbHlzZXMgd291bGQgcHJvdmlkZSBhIGRldGFpbGVkIGV4YW1pbmF0aW9uIG9mIGhvdyB0byBleHRyYWN0IHRoZSBtb3N0IHJlbGlhYmxlL2Jlc3QgaW5kaXZpZHVhbCBkaWZmZXJlbmNlIG1lYXN1cmUgZnJvbSB0YXNrcyB3aXRoIGEgc2V0IG9mIG1lZGlvY3JlIHZhcmlhYmxlcyB0byBiZWdpbiB3aXRoLiBTbyBJIGFtIGNob29zaW5nIHRvIGlnbm9yZSB0aGlzIGZvciBub3cgYnV0IHRoaXMgY2FuIGJlIHJldmlzaXRlZC4KCiMjIyBSYXcgdnMgRERNCgpDaGVja2luZyBERE0gcmVzdWx0cyBpbiB0aGUgYm9vdHN0cmFwcGVkIGVzdGltYXRlcy4gVmFyaWFibGVzIHVzaW5nIGFsbCB0cmlhbHMgYXJlIHNpZ25pZmljYW50bHkgbW9yZSByZWxpYWJsZSBjb21wYXJlZCB0byBkaWZmZXJlbmNlIHNjb3Jlcy4gUmF3IG1lYXN1cmVzIGRvbid0IGRpZmZlciBmcm9tIERETSBwYXJhbWV0ZXJzLiBXaGljaCBERE0gaXMgYmV0dGVyIGRlcGVuZHMgb24gd2hldGhlciBhbGwgdHJpYWxzIGFyZSB1c2VkLgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KdG1wID0gbWVhc3VyZV9sYWJlbHMgJT4lCiAgbXV0YXRlKGR2ID0gYXMuY2hhcmFjdGVyKGR2KSkgJT4lCiAgZmlsdGVyKGRkbV90YXNrID09IDEsIAogICAgICAgICBvdmVyYWxsX2RpZmZlcmVuY2UgIT0gImNvbmRpdGlvbiIpICU+JQogIGRyb3BfbmEoKSAlPiUKICBsZWZ0X2pvaW4oYm9vdF9kZlssYygiZHYiLCAiaWNjIiwgInNwZWFybWFuIildLCBieSA9ICdkdicpCgp0bXAgJT4lCiAgZ3JvdXBfYnkob3ZlcmFsbF9kaWZmZXJlbmNlLCByYXdfZml0LCBydF9hY2MpICU+JQogIHN1bW1hcmlzZShpY2NfbWVkaWFuID0gcXVhbnRpbGUoaWNjLCBwcm9icyA9IDAuNSksCiAgICAgICAgICAgIGljY18yLjUgPSBxdWFudGlsZShpY2MsIHByb2JzID0gMC4wMjUpLAogICAgICAgICAgICBpY2NfOTcuNSA9IHF1YW50aWxlKGljYywgcHJvYnMgPSAwLjk3NSksCiAgICAgICAgICAgIHNwZWFybWFuX21lZGlhbiA9IHF1YW50aWxlKHNwZWFybWFuLCBwcm9icyA9IDAuNSksCiAgICAgICAgICAgIHNwZWFybWFuXzIuNSA9IHF1YW50aWxlKHNwZWFybWFuLCBwcm9icyA9IDAuMDI1KSwKICAgICAgICAgICAgc3BlYXJtYW5fOTcuNSA9IHF1YW50aWxlKHNwZWFybWFuLCBwcm9icyA9IDAuOTc1KSwKICAgICAgICAgICAgbnVtX3ZhcnMgPSBuKCkvMTAwMCkgJT4lCiAgZGF0YXRhYmxlKCkgJT4lCiAgZm9ybWF0Um91bmQoY29sdW1ucz1jKCdpY2NfbWVkaWFuJywgJ2ljY18yLjUnLCAnaWNjXzk3LjUnLCAnc3BlYXJtYW5fbWVkaWFuJywgJ3NwZWFybWFuXzIuNScsICdzcGVhcm1hbl85Ny41JyksIGRpZ2l0cz0zKQpgYGAKCmBgYHtyfQpzdW1tYXJ5KGxtZXJUZXN0OjpsbWVyKGljYyB+IG92ZXJhbGxfZGlmZmVyZW5jZSpyYXdfZml0ICsgKDF8ZHYpICx0bXApKQpgYGAKCmBgYHtyfQp0bXAgJT4lCiAgZ2dwbG90KGFlcyhmYWN0b3IocmF3X2ZpdCwgbGV2ZWxzID0gYygicmF3IiwgIkVaIiwgImhkZG0iKSwgbGFiZWxzPWMoIlJhdyIsICJFWi1kaWZmdXNpb24iLCAiSGllcmFyY2hpY2FsIGRpZmZ1c2lvbiIpKSwgaWNjLCBmaWxsPWZhY3RvcihydF9hY2MsIGxldmVscyA9IGMoInJ0IiwiYWNjdXJhY3kiLCJvdGhlciIsICJkcmlmdCByYXRlIiwgInRocmVzaG9sZCIsICJub24tZGVjaXNpb24iKSwgbGFiZWxzPWMoIlJlc3BvbnNlIFRpbWUiLCAiQWNjdXJhY3kiLCAiT3RoZXIiLCJEcmlmdCBSYXRlIiwgIlRocmVzaG9sZCIsICJOb24tZGVjaXNpb24iKSkpKSsKICBnZW9tX2JveHBsb3QoKSsKICBmYWNldF93cmFwKH5mYWN0b3Iob3ZlcmFsbF9kaWZmZXJlbmNlLCBsZXZlbHM9Yygib3ZlcmFsbCIsICJkaWZmZXJlbmNlIiksIGxhYmVscz1jKCJPdmVyYWxsIiwgIkRpZmZlcmVuY2UiKSkpKwogIHRoZW1lX2J3KCkrCiAgeWxhYigiSUNDIikrCiAgeGxhYigiIikrCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKZ2dzYXZlKCdCb290c3RyYXBfRERNX0NvbXAuanBnJywgZGV2aWNlID0gImpwZWciLCBwYXRoID0gIi9Vc2Vycy96ZXluZXBlbmthdmkvRHJvcGJveC9Qb2xkcmFja0xhYi9TUk9fUmV0ZXN0X0FuYWx5c2VzL291dHB1dC9maWd1cmVzLyIsIHdpZHRoID0gMjQsIGhlaWdodCA9IDYsIHVuaXRzID0gImluIiwgbGltaXRzaXplID0gRkFMU0UpCmBgYAoKIyMjIyBERE0gVmFyaWFuY2UgYnJlYWtkb3duCgpXaGF0IGRvZXMgdGhlIHZhcmlhbmNlIGJyZWFrZG93biBsb29rIGxpa2UgZm9yIERETSB2YXJpYWJsZXMgc2VwYXJhdGVseT8KCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnRtcCA9IHJlbF9kZiAlPiUKICBtdXRhdGUodmFyX3N1YnNfcGN0ID0gdmFyX3N1YnMvKHZhcl9zdWJzK3Zhcl9pbmQrdmFyX3Jlc2lkKSoxMDAsCiAgICAgICAgIHZhcl9pbmRfcGN0ID0gdmFyX2luZC8odmFyX3N1YnMrdmFyX2luZCt2YXJfcmVzaWQpKjEwMCwgCiAgICAgICAgIHZhcl9yZXNpZF9wY3QgPSB2YXJfcmVzaWQvKHZhcl9zdWJzK3Zhcl9pbmQrdmFyX3Jlc2lkKSoxMDApICU+JQogIHNlbGVjdChkdiwgdGFzaywgdmFyX3N1YnNfcGN0LCB2YXJfaW5kX3BjdCwgdmFyX3Jlc2lkX3BjdCkgJT4lCiAgbXV0YXRlKGR2ID0gZmFjdG9yKGR2LCBsZXZlbHMgPSBkdltvcmRlcih0YXNrKV0pKSAlPiUKICBzZXBhcmF0ZShkdiwgYygidGFza19ncm91cCIsICJ2YXIiKSwgc2VwPSJcXC4iLHJlbW92ZT1GQUxTRSxleHRyYT0ibWVyZ2UiKSAlPiUKICBtdXRhdGUodGFza19ncm91cCA9IGZhY3Rvcih0YXNrX2dyb3VwLCBsZXZlbHMgPSB0YXNrX2dyb3VwW29yZGVyKHRhc2spXSkpICU+JQogIGFycmFuZ2UodGFza19ncm91cCwgdmFyX3N1YnNfcGN0KSAlPiUKICBtdXRhdGUocmFuayA9IHJvd19udW1iZXIoKSkgJT4lCiAgYXJyYW5nZSh0YXNrLCB0YXNrX2dyb3VwLCByYW5rKSAlPiUKICBnYXRoZXIoa2V5LCB2YWx1ZSwgLWR2LCAtdGFza19ncm91cCwgLXZhciwgLXRhc2ssIC1yYW5rKSAlPiUKICB1bmdyb3VwKCklPiUKICBtdXRhdGUodGFza19ncm91cCA9IGdzdWIoIl8iLCAiICIsIHRhc2tfZ3JvdXApLAogICAgICAgICB2YXIgPSBnc3ViKCJfIiwgIiAiLCB2YXIpKSAlPiUKICBtdXRhdGUodGFza19ncm91cCA9IGlmZWxzZSh0YXNrX2dyb3VwID09ICJwc3ljaG9sb2dpY2FsIHJlZnJhY3RvcnkgcGVyaW9kIHR3byBjaG9pY2VzIiwgInBzeWNob2xvZ2ljYWwgcmVmcmFjdG9yeSBwZXJpb2QiLCBpZmVsc2UodGFza19ncm91cCA9PSAiYW5nbGluZyByaXNrIHRhc2sgYWx3YXlzIHN1bm55IiwgImFuZ2xpbmcgcmlzayB0YXNrIix0YXNrX2dyb3VwKSkpICU+JQogIG11dGF0ZSh0YXNrX2dyb3VwID0gZ3N1Yigic3VydmV5IiwgIiIsIHRhc2tfZ3JvdXApKSAlPiUKICBmaWx0ZXIodGFzaz09InRhc2siLAogICAgICAgICBncmVwbCgiRVp8aGRkbSIsIGR2KSklPiUKICBhcnJhbmdlKHRhc2tfZ3JvdXAsIHJhbmspCmxhYmVscyA9IHRtcCAlPiUKICBkaXN0aW5jdChkdiwgLmtlZXBfYWxsPVQpCgpwMSA8LSB0bXAgJT4lCiAgZ2dwbG90KGFlcyh4PWZhY3RvcihyYW5rKSwgeT12YWx1ZSwgZmlsbD1mYWN0b3Ioa2V5LCBsZXZlbHMgPSBjKCJ2YXJfcmVzaWRfcGN0IiwgInZhcl9pbmRfcGN0IiwgInZhcl9zdWJzX3BjdCIpKSkpKwogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JywgYWxwaGEgPSAwLjc1LCBjb2xvcj0nIzAwQkZDNCcpKwogIHNjYWxlX3hfZGlzY3JldGUoYnJlYWtzID0gbGFiZWxzJHJhbmssCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gbGFiZWxzJHZhcikrCiAgY29vcmRfZmxpcCgpKwogIGZhY2V0X2dyaWQodGFza19ncm91cH4uLCBzd2l0Y2ggPSAieSIsIHNjYWxlcyA9ICJmcmVlX3kiLCBzcGFjZSA9ICJmcmVlX3kiKSArCiAgdGhlbWUocGFuZWwuc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwgCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLAogICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZT0xODApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5ODUiKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJykrCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICBzY2FsZV9maWxsX21hbnVhbChicmVha3MgPSBjKCJ2YXJfc3Vic19wY3QiLCAidmFyX2luZF9wY3QiLCAidmFyX3Jlc2lkX3BjdCIpLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiVmFyaWFuY2UgYmV0d2VlbiBpbmRpdmlkdWFscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWYXJpYW5jZSBiZXR3ZWVuIHNlc3Npb25zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVycm9yIHZhcmlhbmNlIiksCiAgICAgICAgICAgICAgICAgIHZhbHVlcz1jKCJncmV5NjUiLCAiZ3JleTQ1IiwgImdyZXkyNSIpKSsKICB5bGFiKCIiKSsKICB4bGFiKCIiKQoKZ2dzYXZlKCdWYXJpYW5jZV9CcmVha2Rvd25fUGxvdF9ERE0uanBnJywgcGxvdCA9IHAxLCBkZXZpY2UgPSAianBlZyIsIHBhdGggPSAiL1VzZXJzL3pleW5lcGVua2F2aS9Ecm9wYm94L1BvbGRyYWNrTGFiL1NST19SZXRlc3RfQW5hbHlzZXMvb3V0cHV0L2ZpZ3VyZXMiLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSAyMCwgdW5pdHMgPSAiaW4iKQpgYGAKCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCcvVXNlcnMvemV5bmVwZW5rYXZpL0Ryb3Bib3gvUG9sZHJhY2tMYWIvU1JPX1JldGVzdF9BbmFseXNlcy9vdXRwdXQvZmlndXJlcy9WYXJpYW5jZV9CcmVha2Rvd25fUGxvdF9ERE0uanBnJykKYGBgCgpTdW1tYXJpemluZyBpdCBieSByYXcgdnMgZml0IGFuZCBmb3IgZWFjaCBwYXJhbWV0ZXIKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnRtcCA9IG1lYXN1cmVfbGFiZWxzICU+JQogIG11dGF0ZShkdiA9IGFzLmNoYXJhY3RlcihkdikpICU+JQogIGZpbHRlcihkZG1fdGFzayA9PSAxLCAKICAgICAgICAgb3ZlcmFsbF9kaWZmZXJlbmNlICE9ICJjb25kaXRpb24iKSAlPiUKICBkcm9wX25hKCkgJT4lCiAgbGVmdF9qb2luKGJvb3RfZGZbLGMoImR2IiwgImljYyIsICJ2YXJfc3VicyIsICJ2YXJfaW5kIiwgInZhcl9yZXNpZCIpXSwgYnkgPSAnZHYnKSAlPiUKICBtdXRhdGUodmFyX3N1YnNfcGN0ID0gKHZhcl9zdWJzLyh2YXJfc3Vicyt2YXJfaW5kK3Zhcl9yZXNpZCkpKjEwMCwKICAgICAgICAgdmFyX2luZF9wY3Q9ICh2YXJfaW5kLyh2YXJfc3Vicyt2YXJfaW5kK3Zhcl9yZXNpZCkpKjEwMCwKICAgICAgICAgdmFyX3Jlc2lkX3BjdCA9ICh2YXJfcmVzaWQvKHZhcl9zdWJzK3Zhcl9pbmQrdmFyX3Jlc2lkKSkqMTAwKSAlPiUKICBzZWxlY3QoLXRhc2ssIC1kZG1fdGFzaywgLW51bV9hbGxfdHJpYWxzLCAtdmFyX3N1YnMsIC12YXJfaW5kLCAtdmFyX3Jlc2lkKSAlPiUKICBnYXRoZXIoa2V5LCB2YWx1ZSwgLWR2LCAtb3ZlcmFsbF9kaWZmZXJlbmNlLCAtcmF3X2ZpdCwgLXJ0X2FjYywgLWljYykKCnRtcCAlPiUKICBnZ3Bsb3QoYWVzKGZhY3RvcihyYXdfZml0LCBsZXZlbHMgPSBjKCJyYXciLCAiRVoiLCAiaGRkbSIpLCBsYWJlbHM9YygiUmF3IiwgIkVaLWRpZmZ1c2lvbiIsICJIaWVyYXJjaGljYWwgZGlmZnVzaW9uIikpLCB2YWx1ZSwgZmlsbD1mYWN0b3IocnRfYWNjLCBsZXZlbHMgPSBjKCJydCIsImFjY3VyYWN5Iiwib3RoZXIiLCAiZHJpZnQgcmF0ZSIsICJ0aHJlc2hvbGQiLCAibm9uLWRlY2lzaW9uIiksIGxhYmVscz1jKCJSZXNwb25zZSBUaW1lIiwgIkFjY3VyYWN5IiwgIk90aGVyIiwiRHJpZnQgUmF0ZSIsICJUaHJlc2hvbGQiLCAiTm9uLWRlY2lzaW9uIikpKSkrCiAgZ2VvbV9ib3hwbG90KCkrCiAgZmFjZXRfZ3JpZChmYWN0b3Ioa2V5LCBsZXZlbHMgPSBjKCJ2YXJfc3Vic19wY3QiLCAidmFyX2luZF9wY3QiLCAidmFyX3Jlc2lkX3BjdCIpLCBsYWJlbHM9YygiVmFyaWFuY2UgYmV0d2VlbiBzdWJqZWN0cyIsICJWYXJpYW5jZSBiZXR3ZWVuIGluZGl2aWR1YWxzIiwgIkVycm9yIHZhcmlhbmNlIikpfmZhY3RvcihvdmVyYWxsX2RpZmZlcmVuY2UsIGxldmVscz1jKCJvdmVyYWxsIiwgImRpZmZlcmVuY2UiKSwgbGFiZWxzPWMoIk92ZXJhbGwiLCAiRGlmZmVyZW5jZSIpKSkrCiAgdGhlbWVfYncoKSsKICB5bGFiKCIlIG9mIHRvdGFsIHZhcmlhbmNlIikrCiAgeGxhYigiIikrCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKZ2dzYXZlKCdWYXJpYW5jZV9CcmVha2Rvd25fUGxvdF9ERE1fc3VtbWFyeS5qcGcnLCBkZXZpY2UgPSAianBlZyIsIHBhdGggPSAiL1VzZXJzL3pleW5lcGVua2F2aS9Ecm9wYm94L1BvbGRyYWNrTGFiL1NST19SZXRlc3RfQW5hbHlzZXMvb3V0cHV0L2ZpZ3VyZXMiLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4LCB1bml0cyA9ICJpbiIpCmBgYAoKRG8gdGhlc2UgZGlmZmVyIHN0YXRpc3RpY2FsbHk/CgpUaGUgcGxvdCBkb2VzIG5vdCBzdWdnZXN0IHNvIGJ1dCB0aGlzIG1vZGVsIGlzIGdpdmluZyBhIHdhcm5pbmcgYW5kIHZlcnkgaGlnaCB0IHZhbHVlcy4gSG93IGVsc2Ugc2hvdWxkIEkgYmUgY2hlY2tpbmcgZm9yIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlc2UgZGlzdHJpYnV0aW9ucz8KCmBgYHtyfQpzdW1tYXJ5KGxtZXIodmFsdWV+a2V5Km92ZXJhbGxfZGlmZmVyZW5jZSpyYXdfZml0KygxfGR2KSwgdG1wKSkKYGBgCgojIyMjIENoYW5nZSBpbiBwYXJhbWV0ZXIgdmFsdWVzIGRlcGVuZGluZyBvbiBzYW1wbGUKCkhvdyBtdWNoIGRvIHBhcmFtZXRlciB2YWx1ZXMgY2hhbmdlIGRlcGVuZGluZyBvbiB3aGV0aGVyIHRoZSBtb2RlbCB3YXMgZml0IHVzaW5nIHRoZSB3aG9sZSBzYW1wbGUgdnMgb25seSB0aGUgcmV0ZXN0IHNhbXBsZS4gRWFjaCBwb2ludCBpbiB0aGVzZSBncmFwaHMgaXMgYSBzdWJqZWN0J3MgcGFyYW1ldGVyIGVzdGltYXRlcy4gVGhlcmUgaXMgYWxtb3N0IG5vIGNoYW5nZSBmb3IgYW55IG9mIHRoZSBFWiBwYXJhbWV0ZXJzICh0aG91Z2ggc2hvdWxkbid0IHRoaXMgaGF2ZSBiZWVuIDA/KS4gRm9yIHRoZSBIRERNIHBhcmFtZXRlcnMgbW9zdCBvZiB0aGUgY2hhbmdlcyBhcmUgaGFwcGVuaW5nIGZvciBkcmlmdCByYXRlcyBidXQgdGhleSBkb24ndCBhcHBlYXIgdG8gYmUgc3lzdGVtYXRpY2FsbHkgaGlnaGVyIG9yIGxvd2VyLgoKSSdtIG5vdCBlbnRpcmVseSBzdXJlIHdoYXQgdG8gbWFrZSBvZiB0aGlzLiBBIHN5c3RlbWF0aWMgY2hhbmdlIHdvdWxkIGhhdmUgbWVhbnQgdGhhdCB0aGUgcmFua2luZyByZW1haW5lZCB0aGUgc2FtZSByZWdhcmRsZXNzIG9mIHRoZSBzYW1wbGUgc2l6ZS4gV2hlbiB0aGUgY2hhbmdlIGlzIG5vbi1zeXN0ZW1hdGljIGluIHRoaXMgd2F5IHRoZW4gYSBnaXZlbiBzdWJqZWN0IHRoYXQgaGFzIGhpZ2ggaGlnaGVyIGRyaWZ0IHJhdGVzIHRoYW4gbW9zdCBvZiB0aGUgcGVvcGxlIGluIHRoZSBmdWxsIHNhbXBsZSBjYW4gYXBwZWFyIHRvIGhhdmUgbG93ZXIgZHJpZnQgcmF0ZXMgdGhhbiB0aGUgc2FtZSBwZW9wbGUgd2hlbiBmaXQgb24gdGhlIHJldGVzdCBzYW1wbGUgb25seS4gKG5vdGUgdGhhdCBhIHQtdGVzdCBpcyBub3Qgc2lnbmlmaWNhbnQpCgpPZiBjb3Vyc2UgdGhlc2UgcGFyYW1ldGVyIGVzdGltYXRlcyB0aGVtc2VsdmVzIGFyZSBub3QgdmVyeSBpbnRlcnByZXRhYmxlIGluIHRoZWlyICdnb29kbmVzcycgYXMgdGhleSBkb24ndCByZWZsZWN0IGFueXRoaW5nIGFib3V0IG1vZGVsIGZpdHMuIFdoYXQgaXMgdGhlIG1lYXN1cmUgb2YgZml0cyBoZXJlPyBUaGUgdmFyaWFuY2Ugb2YgdGhlIHBvc3Rlcmlvcj8KCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmhkZG1fZnVsbGZpdHMgPC0gdGVzdF9kYXRhX2Z1bGxfc2FtcGxlX2hkZG1bLG5hbWVzKHRlc3RfZGF0YV9mdWxsX3NhbXBsZV9oZGRtKSAlaW4lIG5hbWVzKGhkZG1fcmVmaXRzKV0KCmhkZG1fZnVsbGZpdHMgPSBoZGRtX2Z1bGxmaXRzICU+JQogIGdhdGhlcihkdiwgdmFsdWUsIC1zdWJfaWQpCgpoZGRtX3JlZml0cyAlPiUKICBnYXRoZXIoZHYsIHZhbHVlLCAtc3ViX2lkKSAlPiUKICBsZWZ0X2pvaW4oaGRkbV9mdWxsZml0cywgYnkgPSBjKCJzdWJfaWQiLCAiZHYiKSkgJT4lCiAgcmVuYW1lKGZ1bGxmaXQgPSB2YWx1ZS55LCByZWZpdCA9IHZhbHVlLngpICU+JQogIGxlZnRfam9pbihtZWFzdXJlX2xhYmVsc1ssYygiZHYiLCAicmF3X2ZpdCIsICJydF9hY2MiKV0sIGJ5PSJkdiIpICU+JQogIGZpbHRlcihydF9hY2MgJWluJSBjKCJkcmlmdCByYXRlIiwibm9uLWRlY2lzaW9uIiwgInRocmVzaG9sZCIpKSAlPiUKICBnZ3Bsb3QoYWVzKGZ1bGxmaXQsIHJlZml0KSkrCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9cnRfYWNjKSkrCiAgZmFjZXRfd3JhcCh+cmF3X2ZpdCkrCiAgdGhlbWVfYncoKSsKICBnZW9tX2FibGluZShzbG9wZT0xLCBpbnRlcmNlcHQ9MCkrCiAgeGxhYigiRml0IG9uIGZ1bGwgc2FtcGxlIikrCiAgeWxhYigiRml0IG9uIHJldGVzdCBzYW1wbGUiKSsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMjIyBQYXJhbWV0ZXIgcmVsaWFiaWxpdHkgZGVwZW5kaW5nIG9uIHNhbXBsZSBzaXplCgpUaGVyZSBkb2Vzbid0IHNlZW0gdG8gYmUgYW4gZWZmZWN0IGxvb2tpbmcgYXQgdGhlIGdyYXBoIGJ1dCB0aGUgbXVsdGlsZXZlbCBtb2RlbCBzZWVtcyB0byBzaG93IGEgdmVyeSBzaWduaWZpY2FudCBidXQgdGlueSBlZmZlY3QuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQp0bXAgPC0gcmVhZC5jc3YoJy9Vc2Vycy96ZXluZXBlbmthdmkvRHJvcGJveC9Qb2xkcmFja0xhYi9TUk9fUmV0ZXN0X0FuYWx5c2VzL2lucHV0L2FsbF9kZG1fc2FtcGxlX3NpemVfc3VtbWFyeS5jc3YnKQoKZ2dwbG90bHkodG1wICU+JQogIHNlbGVjdChkdiwgTiwgaWNjX21lZGlhbikgJT4lCiAgbGVmdF9qb2luKG1lYXN1cmVfbGFiZWxzWyxjKCJkdiIsICJyYXdfZml0IiwgInJ0X2FjYyIpXSwgYnk9ImR2IikgJT4lCiAgZ2dwbG90KGFlcyhOLCBpY2NfbWVkaWFuLCBjb2xvcj1kdikpKwogIGdlb21fbGluZSgpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKSsKICB4bGFiKCJTYW1wbGUgU2l6ZSIpKwogIHlsYWIoIk1lZGlhbiBJQ0MiKSkKYGBgCgpgYGB7cn0Kc3VtbWFyeShsbWVyKGljY19tZWRpYW4gfiBOICsgKDF8ZHYpLCB0bXApKQpgYGAKCiMjIyMgSXMgdGhlIEggaW4gSERETSBpbXBvcnRhbnQ/CgpUQkQuIFN0aWxsIG5lZWQgdG8gZmlndXJlIG91dCBob3cgdG8gdHVybiBvZmYgdGhlIEguCgojIyBDb21wbGV0aW9uIHRpbWVzCgojIyMgU3ViamVjdCBsZXZlbAoKRG8gcGVvcGxlIGRpZmZlciBpbiBob3cgbXVjaCB0aGVpciBzY29yZXMgY2hhbmdlIGRlcGVuZGluZyBvbiBob3cgbWFueSBkYXlzIGl0IGhhcyBiZWVuIHNpbmNlIHRoZXkgY29tcGxldGVkIHRoZSBpbml0aWFsIGJhdHRlcnk/ICAKCk1ha2UgZGF0YSBmcmFtZSB3aXRoIGRpZmZlcmVuY2UgYmV0d2VlbiB0d28gc2NvcmVzIGZvciBlYWNoIG1lYXN1cmUgZm9yIGVhY2ggc3ViamVjdC4gU2luY2UgdGhlIHNjb3JlcyBmb3IgZGlmZmVyZW50IG1lYXN1cmVzIGFyZSBvbiBkaWZmZXJlbnQgc2NhbGVzIGZvciBjb21wYXJhYmlsaXR5IHRoZSBkaWZmZXJlbmNlIHNjb3JlcyBhcmUgc2NhbGVkIChpLmUuIGRpdmlkZWQgYnkgdGhlaXIgcm9vdCBtZWFuIHNxdWFyZSkgYnV0IG5vdCBjZW50ZXJlZCBzbyBhIHZhbHVlIG9mIDAgZm9yIHRoZSBkaWZmZXJlbmNlIHNjb3JlcyB3b3VsZCBpbmRpY2F0ZSBhIGxhY2sgb2YgYSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHNjb3JlcyBvZiBhIHN1YmplY3QuCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQp0MV8yX2RpZmZlcmVuY2UgPSBkYXRhLmZyYW1lKCkKCmZvcihpIGluIDE6bGVuZ3RoKG51bWVyaWNfY29scykpewogIHRtcCA9IG1hdGNoX3QxX3QyKG51bWVyaWNfY29sc1tpXSxmb3JtYXQ9J3dpZGUnKQogIHRtcCA9IHRtcCAlPiUgCiAgICAjIG11dGF0ZShkaWZmZXJlbmNlID0gc2NhbGUoYDJgIC0gYDFgKSkKICBtdXRhdGUoZGlmZmVyZW5jZSA9IHNjYWxlKGAyYCAtIGAxYCwgY2VudGVyPUYpKQogIHQxXzJfZGlmZmVyZW5jZSA9IHJiaW5kKHQxXzJfZGlmZmVyZW5jZSwgdG1wKQp9Cgp0MV8yX2RpZmZlcmVuY2UkZGlmZmVyZW5jZSA9IGFzLmRhdGEuZnJhbWUodDFfMl9kaWZmZXJlbmNlJGRpZmZlcmVuY2UpJFYxCmBgYAoKYGBge3IgZWNobz1GQUxTRX0Kcm0odG1wLCBpKQpgYGAKCkFkZCBjb21wbGV0aW9uIGRhdGVzIHRvIHRoaXMgZGF0YSBmcmFtZS4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnQxXzJfZGlmZmVyZW5jZSA9IG1lcmdlKHQxXzJfZGlmZmVyZW5jZSwgY29tcF9kYXRlc1ssYygnc3ViX2lkJywgJ2RheXNfYnR3JyldLCBieT0nc3ViX2lkJykKYGBgCgpgYGB7ciBlY2hvPUZBTFNFfQpybSh0ZXN0X2NvbXBfZGF0ZSwgcmV0ZXN0X2NvbXBfZGF0ZSwgY29tcF9kYXRlcykKYGBgCgpUaGUgZWZmZWN0IG9mIG51bWJlciBvZiBkYXlzIGluIGJldHdlZW4gaW4gdGhlIGZ1bGwgbW9kZWwgd2hlcmUgdGhlIGRpZmZlcmVuY2Ugc2NvcmVzIGFyZSByZWdyZXNzZWQgb24gYSBmaXhlZCBlZmZlY3QgZm9yIG1lYXN1cmUgYW5kIGRheXMgYmV0d2VlbiB0aGUgdHdvIHNjb3JlcyBhbmQgcmFuZG9tIGludGVyY2VwdHMgZm9yIGVhY2ggc3ViamVjdCAoKlNob3VsZCB0aGlzIG1vZGVsIGluY2x1ZGUgdGhlIGludGVyYWN0aW9uIGJldHdlZW4gdGhlIGZpeGVkIGVmZmVjdHM/KikuIFNpbmNlIHRoZXJlIGFyZSBvdmVyIDQwMCBtZWFzdXJlcyB0aGUgb3V0cHV0IG9mIHRoZSBmdWxsIG1vZGVsIGlzIG5vdCBwcmVzZW50ZWQgaGVyZS4gSW5zdGVhZCBiZWxvdyBhcmUgdGhlIGNvZWZmaWNpZW50IGZvciB0aGUgZml4ZWQgZWZmZWN0IG9mIGRheXMgYmV0d2VlbiBjb21wbGV0aW9uIHRpbWVzIGFuZCBpdHMgdCB2YWx1ZS4KCmBgYHtyfQptb2QgPSBsbWVyKGRpZmZlcmVuY2UgfiBkdiArIGRheXNfYnR3ICsgKDF8c3ViX2lkKSwgZGF0YSA9IHQxXzJfZGlmZmVyZW5jZSkKCmRhdGEuZnJhbWUoZXN0aW1hdGU9Y29lZihzdW1tYXJ5KG1vZCkpWyJkYXlzX2J0dyIsIkVzdGltYXRlIl0sIHR2YWw9Y29lZihzdW1tYXJ5KG1vZCkpWyJkYXlzX2J0dyIsInQgdmFsdWUiXSkKYGBgCgpGb3IgdmlzdWFsaXphdGlvbiBwdXJwb3NlcyBJIHN1bW1hcml6ZWQgdGhlIGRpZmZlcmVuY2Ugc2NvcmVzIHBlciBwZXJzb24gYnkgbG9va2luZyBhdCB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIGFuZCBwbG90IHRoYXQgYWdhaW5zdCB0aGUgbnVtYmVyIG9mIGRheXMgYmV0d2VlbiBjb21wbGV0aW9uLgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KdG1wID0gdDFfMl9kaWZmZXJlbmNlICU+JQogIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgc3VtbWFyaXNlKG1lYW5fZGlmZiA9IG1lYW4oZGlmZmVyZW5jZSwgbmEucm09VCksCiAgICAgICAgICAgIGRheXNfYnR3ID0gdW5pcXVlKGRheXNfYnR3KSkKCnRtcCAlPiUKICBnZ3Bsb3QoYWVzKGRheXNfYnR3LCBtZWFuX2RpZmYpKSsKICBnZW9tX3BvaW50KCkrCiAgdGhlbWVfYncoKSsKICB4bGFiKCJEYXlzIGJldHdlZW4gY29tcGxldGlvbiIpKwogIHlsYWIoIk1lYW4gc3RhbmRhcmRpemVkIGRpZmZlcmVuY2UgYmV0d2VlbiB0d28gdGltZSBwb2ludHMiKSsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikKYGBgCgpUbyBjb25maXJtOiB0aGUgc2xvcGUgb2YgdGhpcyBsaW5lIGlzIG5vdCBzaWduaWZpY2FudC4gVGhhdCBpcywgdGhlcmUgZG9lc24ndCBzZWVtIHRvIGJlIGEgc3lzdGVtYXRpYyBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHR3byBtZWFzdXJlbWVudHMgZGVwZW5kaW5nIG9uIHRoZSBudW1iZXIgb2YgZGF5cyBiZXR3ZWVuIHRoZSB0d28gbWVhc3VyZW1lbnRzLgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0Kc3VtbWFyeShsbShtZWFuX2RpZmYgfiBkYXlzX2J0dywgZGF0YT10bXApKQpgYGAKCmBgYHtyIGVjaG89RkFMU0V9CnJtKHRtcCkKYGBgCgojIyMgVGFzayBsZXZlbAoKRm9yIGVhY2ggdmFyaWFibGUgZG9lcyB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIGJldHdlZW4gdHdvIHRpbWUgcG9pbnRzIHZhcnkgYnkgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIGRheXMgYmV0d2VlbiB0aGUgdHdvIHRpbWUgcG9pbnRzPyBOby4gVGhlIHNsb3BlcyBvZiB0aGVzZSBsaW5lcyBvciB0aGUgaW50ZXJhY3Rpb24gaXMgbm90IHNpZ25pZmljYW50LgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KdDFfMl9kaWZmZXJlbmNlIDwtIHQxXzJfZGlmZmVyZW5jZSAlPiUKICBzZXBhcmF0ZShkdiwgYygndGFza19uYW1lJywgJ2V4dHJhXzEnLCAnZXh0cmFfMicpLCBzZXAgPSAnXFwuJyxyZW1vdmU9RkFMU0UpICU+JQogIHNlbGVjdCgtZXh0cmFfMSwgLWV4dHJhXzIpICU+JSAKICBtdXRhdGUodGFzayA9IGlmZWxzZShncmVwbCgic3VydmV5IixkdiksICJzdXJ2ZXkiLCJ0YXNrIiksCiAgICAgICAgICAgdGFzayA9IGlmZWxzZShncmVwbCgiaG9sdCIsZHYpLCAidGFzayIsIHRhc2spKQoKIyBzdW1tYXJ5KGxtZXIoZGlmZmVyZW5jZSB+IGRheXNfYnR3ICsgKHRhc2tfbmFtZXxzdWJfaWQpLCB0MV8yX2RpZmZlcmVuY2UpKQoKdDFfMl9kaWZmZXJlbmNlICU+JQogIG11dGF0ZSh0YXNrID0gaWZlbHNlKGdyZXBsKCJzdXJ2ZXkiLGR2KSwgInN1cnZleSIsInRhc2siKSwKICAgICAgICAgICB0YXNrID0gaWZlbHNlKGdyZXBsKCJob2x0IixkdiksICJ0YXNrIiwgdGFzaykpICU+JQogIGdyb3VwX2J5KGR2KSAlPiUKICBzdW1tYXJpc2UobWVhbl9kaWZmID0gbWVhbihkaWZmZXJlbmNlKSwKICAgICAgICAgICAgbWVhbl9kYXlzX2J0dyA9IG1lYW4oZGF5c19idHcpLAogICAgICAgICAgICB0YXNrID0gdW5pcXVlKHRhc2spKSAlPiUKICBnZ3Bsb3QoYWVzKG1lYW5fZGF5c19idHcsIG1lYW5fZGlmZiwgY29sb3I9dGFzaykpKwogIGdlb21fcG9pbnQoKSsKICB0aGVtZV9idygpKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSsKICB4bGFiKCJBdmVyYWdlIGRheXMgYmV0d2VlbiBjb21wbGV0aW9uIikrCiAgeWxhYigiQXZlcmFnZSBkaWZmZXJlbmNlIGJldHdlZW4gdGltZSBwb2ludHMiKSsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKYGBge3J9CnRtcCA9IHQxXzJfZGlmZmVyZW5jZSAlPiUKICBncm91cF9ieShkdikgJT4lCiAgc3VtbWFyaXNlKG1lYW5fZGlmZiA9IG1lYW4oZGlmZmVyZW5jZSksCiAgICAgICAgICAgIG1lYW5fZGF5c19idHcgPSBtZWFuKGRheXNfYnR3KSwKICAgICAgICAgICAgdGFzayA9IHVuaXF1ZSh0YXNrKSkKCnN1bW1hcnkobG0obWVhbl9kaWZmIH4gbWVhbl9kYXlzX2J0dyp0YXNrLCB0bXApKQpgYGAKCiMjIExlYXJuaW5nIGVmZmVjdHMKCklzIHRoZSB0MiBzY29yZSBoaWdoZXIgZm9yIHRhc2sgdmFyaWFibGVzPyBQbG90dGluZyB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIGJldHdlZW4gdGltZSBwb2ludHMgKGZvciBhbGwgc3ViamVjdHMpIGZvciBlYWNoIGRlcGVuZGVudCB2YXJpYWJsZSBjb2xvcmluZyBieSB0YXNrLiBNb3JlIHBvc2l0aXZlIG9uIHRoZSB5LWF4aXMgbWVhbnMgbW9yZSBpbXByb3ZlbWVudC4gRGlkbid0IHdhbnQgdG8gc3VtbWFyaXplIGl0IGF0IHRhc2sgbGV2ZWwgYmVjYXVzZSBub3QgYWxsIG1lYXN1cmVzIG1pZ2h0IGJlIHRoaW5ncyB3ZSdkIGV4cGVjdCBsZWFybmluZyBlZmZlY3RzIG9uLgoKSXQncyBoYXJkIHRvIGRldGVjdCBhbnkgbWVhbmluZ2Z1bCBnbG9iYWwgY2hhbmdlcy9pbXByb3ZlbWVudHMgZnJvbSB0aGlzIGdyYXBoLiBJdCBzZWVtcyB0aGF0IGZvciBlYWNoIHRhc2sgdGhlcmUgbWlnaHQgYmUgc29tZSB2YXJpYWJsZXMgdGhhdCBoYXZlIGltcHJvdmVkIGF0IHQyIGJ1dCB3aGV0aGVyIHRoZXNlIGFyZSBtZW5haW5nZnVsIGxlYXJuaW5nIGVmZmVjdHMgc2hvdWxkIGJlIGRldGVybWluZWQgYmFzZWQgb24gdGhlIHZhcmlhYmxlLgoKYGBge3J9CnQxXzJfZGlmZmVyZW5jZSAlPiUKICBmaWx0ZXIodGFzayA9PSAidGFzayIpICU+JQogIGdyb3VwX2J5KGR2KSAlPiUKICBzdW1tYXJpc2UobWVhbl9kaWZmID0gbWVhbihkaWZmZXJlbmNlKSwKICAgICAgICAgICAgdGFza19uYW1lID0gdW5pcXVlKHRhc2tfbmFtZSkpICU+JQogIGdncGxvdChhZXMoZHYsbWVhbl9kaWZmLCBjb2xvcj10YXNrX25hbWUpKSsKICBnZW9tX3BvaW50KCkrCiAgdGhlbWVfYncoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpKwogIHhsYWIoIkRlcGVuZGVudCB2YXJpYWJsZSIpKwogIHlsYWIoIkF2ZXJhZ2UgZGlmZmVyZW5jZSBiZXR3ZWVuIHRpbWUgcG9pbnRzIikKYGBgCgojIyBUcmFuc2Zvcm1hdGlvbiBlZmZlY3RzCgpBbGwgcmVzdWx0cyByZXBvcnRlZCBhYm92ZSB3ZXJlIGZvciBub24tdHJhbnNmb3JtZWQgZGVwZW5kZW50IHZhcmlhYmxlcy4KCldlIGNvdWxkIGNvbXBhcmUgdGhlIHJlbGlhYmlsaXR5IChwb2ludCkgZXN0aW1hdGVzIGZvciBtZWFuaW5nZnVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiB0cmFuc2Zvcm1lZCBpbiB0aGUgZnVsbCBkYXRhc2V0IGFuZCB0cmFuc2Zvcm1lZCB0aGUgc2FtZSB3YXkgaW4gdGhlIHJldGVzdCBkYXRhc2V0IGFzIHdlbGwuCgpgYGB7cn0KdGVzdF9kYXRhX3RtcCA8LSB0ZXN0X2RhdGEKcmV0ZXN0X2RhdGFfdG1wIDwtIHJldGVzdF9kYXRhCgp0ZXN0X2RhdGEgPC0gcmVhZC5jc3YoJy9Vc2Vycy96ZXluZXBlbmthdmkvRG9jdW1lbnRzL1BvbGRyYWNrTGFiTG9jYWwvU2VsZl9SZWd1bGF0aW9uX09udG9sb2d5L0RhdGEvUmV0ZXN0XzA5LTI3LTIwMTcvdDFfZGF0YS9tZWFuaW5nZnVsX3ZhcmlhYmxlc19jbGVhbi5jc3YnKQp0ZXN0X2RhdGEkWCA8LSBhcy5jaGFyYWN0ZXIodGVzdF9kYXRhJFgpCm5hbWVzKHRlc3RfZGF0YSlbd2hpY2gobmFtZXModGVzdF9kYXRhKSA9PSAnWCcpXSA8LSdzdWJfaWQnIApyZXRlc3RfZGF0YSA8LSByZWFkLmNzdignL1VzZXJzL3pleW5lcGVua2F2aS9Eb2N1bWVudHMvUG9sZHJhY2tMYWJMb2NhbC9TZWxmX1JlZ3VsYXRpb25fT250b2xvZ3kvRGF0YS9SZXRlc3RfMDktMjctMjAxNy9tZWFuaW5nZnVsX3ZhcmlhYmxlc19jbGVhbi5jc3YnKQpyZXRlc3RfZGF0YSRYIDwtIGFzLmNoYXJhY3RlcihyZXRlc3RfZGF0YSRYKQpuYW1lcyhyZXRlc3RfZGF0YSlbd2hpY2gobmFtZXMocmV0ZXN0X2RhdGEpID09ICdYJyldIDwtJ3N1Yl9pZCcKcmV0ZXN0X2RhdGEgPSByZXRlc3RfZGF0YVtyZXRlc3RfZGF0YSRzdWJfaWQgJWluJSB0ZXN0X2RhdGEkc3ViX2lkLF0KYGBgCgpgYGB7cn0KbnVtZXJpY19jb2xzX21uZ2ZsID0gYygpCgpmb3IoaSBpbiAxOmxlbmd0aChuYW1lcyh0ZXN0X2RhdGEpKSl7CiAgaWYoaXMubnVtZXJpYyh0ZXN0X2RhdGFbLGldKSAmIG5hbWVzKHRlc3RfZGF0YSlbaV0gJWluJSBuYW1lcyhyZXRlc3RfZGF0YSkpewogICAgbnVtZXJpY19jb2xzX21uZ2ZsIDwtIGMobnVtZXJpY19jb2xzX21uZ2ZsLCBuYW1lcyh0ZXN0X2RhdGEpW2ldKQogIH0KfQoKcmVsX2RmX21uZ2ZsIDwtIGRhdGEuZnJhbWUoaWNjID0gcmVwKE5BLCBsZW5ndGgobnVtZXJpY19jb2xzX21uZ2ZsKSkpCgpyb3cubmFtZXMocmVsX2RmX21uZ2ZsKSA8LSBudW1lcmljX2NvbHNfbW5nZmwKCmZvcihpIGluIDE6bGVuZ3RoKG51bWVyaWNfY29sc19tbmdmbCkpewogIHJlbF9kZl9tbmdmbFtudW1lcmljX2NvbHNfbW5nZmxbaV0sICdpY2MnXSA8LSBnZXRfaWNjKG51bWVyaWNfY29sc19tbmdmbFtpXSkKfQoKcmVsX2RmX21uZ2ZsJGR2ID0gcm93Lm5hbWVzKHJlbF9kZl9tbmdmbCkKcm93Lm5hbWVzKHJlbF9kZl9tbmdmbCkgPSBzZXEoMTpucm93KHJlbF9kZl9tbmdmbCkpCnJlbF9kZl9tbmdmbCR0YXNrID0gJ3Rhc2snCnJlbF9kZl9tbmdmbFtncmVwKCdzdXJ2ZXknLCByZWxfZGZfbW5nZmwkZHYpLCAndGFzayddID0gJ3N1cnZleScKcmVsX2RmX21uZ2ZsW2dyZXAoJ2hvbHQnLCByZWxfZGZfbW5nZmwkZHYpLCAndGFzayddID0gInRhc2siCnJlbF9kZl9tbmdmbApgYGAKCmBgYHtyfQpnZ3Bsb3RseShyZWxfZGZfbW5nZmwgJT4lCiAgZmlsdGVyKGdyZXBsKCJsb2dUciIsIGR2KSkgJT4lCiAgbXV0YXRlKGR2ID0gZ3N1YigiLlJlZmxvZ1RyIiwgIiIsIGR2KSwKICAgICAgICAgZHYgPSBnc3ViKCIubG9nVHIiLCAiIiwgZHYpKSAlPiUKICBsZWZ0X2pvaW4ocmVsX2RmWyxjKCJkdiIsICJpY2MiKV0sIGJ5PSJkdiIpICU+JQogIGdncGxvdChhZXMoaWNjLngsIGljYy55LCBjb2xvcj10YXNrLCBsYWJlbD1kdikpKwogIGdlb21fcG9pbnQoKSsKICB0aGVtZV9idygpKwogIHhsYWIoIlJlbGlhYmlsaXR5IGZvciB0cmFuc2Zvcm1lZCB2YXJpYWJsZSIpKwogIHlsYWIoIlJlbGlhYmlsaXR5IGZvciByYXcgdmFyaWFibGUiKSsKICBnZW9tX2FibGluZShzbG9wZT0xLCBpbnRlcmNlcHQ9MCksCiAgbGFiZWw9ZHYpCmBgYA==